Anno editing label/category error states (#1048)

* anno error states

* label validation should not treat empty string as error

* disable Submit if no label or category entered

* edit category name error states

* flex start

* pr cleanup

* label name validation fixes

* PR comment responses
This commit is contained in:
Colin Megill
2019-11-21 19:08:29 -05:00
committed by GitHub
parent ee62dd355f
commit c2ededfc62
3 changed files with 227 additions and 67 deletions
+106 -28
View File
@@ -31,19 +31,26 @@ class CategoryValue extends React.Component {
constructor(props) {
super(props);
this.state = {
editedLabelText: ""
editedLabelText: String(
props.categoricalSelection[props.metadataField].categoryValues[
props.categoryIndex
]
).valueOf()
};
}
handleDeleteValue = () => {
const {
dispatch,
metadataField,
categoryIndex,
categoricalSelection
} = this.props;
getLabel = () => {
const { metadataField, categoryIndex, categoricalSelection } = this.props;
const category = categoricalSelection[metadataField];
const label = category.categoryValues[categoryIndex];
return label;
};
handleDeleteValue = () => {
const { dispatch, metadataField } = this.props;
const label = this.getLabel();
dispatch({
type: "annotation: delete label",
metadataField,
@@ -52,14 +59,8 @@ class CategoryValue extends React.Component {
};
handleAddCurrentSelectionToThisLabel = () => {
const {
dispatch,
metadataField,
categoryIndex,
categoricalSelection
} = this.props;
const category = categoricalSelection[metadataField];
const label = category.categoryValues[categoryIndex];
const { dispatch, metadataField, categoryIndex } = this.props;
const label = this.getLabel();
dispatch({
type: "annotation: label current cell selection",
metadataField,
@@ -69,15 +70,9 @@ class CategoryValue extends React.Component {
};
handleEditValue = () => {
const {
dispatch,
metadataField,
categoryIndex,
categoricalSelection
} = this.props;
const { dispatch, metadataField, categoryIndex } = this.props;
const { editedLabelText } = this.state;
const category = categoricalSelection[metadataField];
const label = category.categoryValues[categoryIndex];
const label = this.getLabel();
dispatch({
type: "annotation: label edited",
editedLabel: editedLabelText,
@@ -85,7 +80,80 @@ class CategoryValue extends React.Component {
categoryIndex,
label
});
this.setState({ editedLabelText: "" });
};
valueNameErrorMessage = () => {
const { editedLabelText } = this.state;
const err = this.valueNameError();
if (!err) return null;
let markup = null;
if (err === "empty_string") {
markup = (
<span
style={{
fontStyle: "italic",
fontSize: 12,
marginTop: 5,
color: Colors.ORANGE3
}}
>
{"Label cannot be blank"}
</span>
);
} else if (err === "duplicate") {
markup = (
<span
style={{
fontStyle: "italic",
fontSize: 12,
marginTop: 5,
color: Colors.ORANGE3
}}
>
{"Label must be unique"}
</span>
);
} else if (err === "characters") {
markup = (
<span
style={{
fontStyle: "italic",
fontSize: 12,
marginTop: 5,
color: Colors.ORANGE3
}}
>
{"Only alphanumeric and underscore allowed"}
</span>
);
}
return markup;
};
valueNameError = () => {
const { editedLabelText } = this.state;
const { categoricalSelection, metadataField, categoryIndex } = this.props;
let err = null;
const category = categoricalSelection[metadataField];
const displayString = String(
category.categoryValues[categoryIndex]
).valueOf();
if (editedLabelText === "") {
err = "empty_string";
} else if (
category.categoryValues.indexOf(editedLabelText) > -1 &&
editedLabelText !== displayString
) {
err = "duplicate";
} else if (!AnnotationsHelpers.isLegalAnnotationName(editedLabelText)) {
err = "characters";
}
return err;
};
activateEditLabelMode = () => {
@@ -115,7 +183,7 @@ class CategoryValue extends React.Component {
});
};
shouldComponentUpdate = nextProps => {
shouldComponentUpdate = (nextProps, nextState) => {
/*
Checks to see if at least one of the following changed:
* world state
@@ -125,7 +193,7 @@ class CategoryValue extends React.Component {
If and only if true, update the component
*/
const { props } = this;
const { props, state } = this;
const { metadataField, categoryIndex, categoricalSelection } = props;
const { categoricalSelection: newCategoricalSelection } = nextProps;
@@ -141,13 +209,15 @@ class CategoryValue extends React.Component {
const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor;
const annotationsChange = props.annotations !== nextProps.annotations;
const crossfilterChange = props.crossfilter !== nextProps.crossfilter;
const editingLabel = state.editedLabelText !== nextState.editedLabelText;
return (
valueSelectionChange ||
worldChange ||
colorAccessorChange ||
annotationsChange ||
crossfilterChange
crossfilterChange ||
editingLabel
);
};
@@ -222,6 +292,8 @@ class CategoryValue extends React.Component {
flippedProps
} = this.props;
const { editedLabelText } = this.state;
if (!categoricalSelection) return null;
const category = categoricalSelection[metadataField];
@@ -347,6 +419,9 @@ class CategoryValue extends React.Component {
<form
onSubmit={e => {
e.preventDefault();
if (this.valueNameError()) {
return;
}
this.handleEditValue();
}}
>
@@ -357,6 +432,7 @@ class CategoryValue extends React.Component {
}}
small
autoFocus
intent={this.valueNameError() ? "warning" : "none"}
onChange={e => {
this.setState({ editedLabelText: e.target.value });
}}
@@ -365,6 +441,7 @@ class CategoryValue extends React.Component {
<Button
minimal
style={{ position: "relative", top: -1 }}
disabled={this.valueNameError()}
type="button"
icon="small-tick"
data-testclass="submitEdit"
@@ -373,6 +450,7 @@ class CategoryValue extends React.Component {
/>
}
/>
{this.valueNameErrorMessage()}
</form>
) : null}
{/*