Improve label picking (#1179)

* add simple error message helper

* port all label name pickers to use the new LabelInput component

* use pure components where possible

* cleanup

* more cleanup

* lint

* change new label prompt
This commit is contained in:
Bruce Martin
2020-02-28 15:46:40 -07:00
committed by GitHub
parent 1e4381ab7f
commit bf7d7342d5
27 changed files with 418 additions and 576 deletions
@@ -1,20 +1,17 @@
import React from "react";
import { connect } from "react-redux";
import AnnoDialog from "./annoDialog";
import AnnoInputs from "./annoInputs";
import { labelErrorMessage, isLabelErroneous } from "./labelUtil";
import LabelInput from "./labelInput";
import { labelPrompt, isLabelErroneous } from "./labelUtil";
@connect(state => ({
colorAccessor: state.colors.colorAccessor,
categoricalSelection: state.categoricalSelection,
annotations: state.annotations,
universe: state.universe,
ontology: state.ontology,
ontologyLoading: state.ontology?.loading,
ontologyEnabled: state.ontology?.enabled
ontology: state.ontology
}))
class Category extends React.Component {
class Category extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
@@ -22,14 +19,15 @@ class Category extends React.Component {
};
}
disableAddNewLabelMode = () => {
disableAddNewLabelMode = e => {
const { dispatch } = this.props;
dispatch({
type: "annotation: disable add new label mode"
});
this.setState({
newLabelText: ""
});
dispatch({
type: "annotation: disable add new label mode"
});
if (e) e.preventDefault();
};
handleAddNewLabelToCategory = e => {
@@ -46,7 +44,7 @@ class Category extends React.Component {
e.preventDefault();
};
addLabelAndAssignCells = () => {
addLabelAndAssignCells = e => {
const { dispatch, metadataField } = this.props;
const { newLabelText } = this.state;
@@ -57,18 +55,7 @@ class Category extends React.Component {
newLabelText,
assignSelectedCells: true
});
};
handleCreateArbitraryLabel = newLabelTextNotInOntology => {
const { dispatch, metadataField } = this.props;
this.disableAddNewLabelMode();
dispatch({
type: "annotation: add new label to category",
metadataField,
newLabelText: newLabelTextNotInOntology,
assignSelectedCells: false
});
e.preventDefault();
};
labelNameError = name => {
@@ -76,23 +63,18 @@ class Category extends React.Component {
return isLabelErroneous(name, metadataField, ontology, universe.schema);
};
labelNameErrorMessage = name => {
const { metadataField, ontology, universe } = this.props;
return labelErrorMessage(name, metadataField, ontology, universe.schema);
instruction = label => {
return labelPrompt(this.labelNameError(label), "New, unique label", ":");
};
/* leaky to have both of these in multiple components */
handleChoice = e => {
this.setState({ newLabelText: e.target });
};
handleTextChange = text => {
this.setState({ newLabelText: text });
handleChangeOrSelect = label => {
this.setState({ newLabelText: label });
};
render() {
const { newLabelText } = this.state;
const { metadataField, annotations, ontologyEnabled } = this.props;
const { metadataField, annotations, ontology } = this.props;
const ontologyEnabled = ontology?.enabled ?? false;
return (
<>
@@ -106,27 +88,26 @@ class Category extends React.Component {
"data-testid": `${metadataField}:submit-label`
}}
title="Add new label to category"
instruction="New, unique label name:"
instruction={this.instruction(newLabelText)}
cancelTooltipContent="Close this dialog without adding a label."
primaryButtonText="Add label"
secondaryButtonText="Add label and assign currently selected cells"
handleSecondaryButtonSubmit={this.addLabelAndAssignCells}
text={newLabelText}
validationError={this.labelNameError(newLabelText)}
errorMessage={this.labelNameErrorMessage(newLabelText)}
handleSubmit={this.handleAddNewLabelToCategory}
handleCancel={this.disableAddNewLabelMode}
annoInput={
<AnnoInputs
useSuggest={ontologyEnabled}
text={newLabelText}
inputProps={{ "data-testid": `${metadataField}:new-label-name` }}
handleCreateArbitraryLabel={this.handleCreateArbitraryLabel}
handleItemChange={this.handleSuggestActiveItemChange}
handleChoice={this.handleChoice}
handleTextChange={this.handleTextChange}
isTextInvalid={this.labelNameError}
isTextInvalidErrorMessage={this.labelNameErrorMessage}
<LabelInput
labelSuggestions={ontologyEnabled ? ontology.terms : null}
onChange={this.handleChangeOrSelect}
onSelect={this.handleChangeOrSelect}
inputProps={{
"data-testid": `${metadataField}:new-label-name`,
leftIcon: "tag",
intent: "none",
autoFocus: true
}}
/>
}
/>