mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 18:48:12 +08:00
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:
@@ -64,9 +64,11 @@ class Categories extends React.Component {
|
|||||||
|
|
||||||
categoryNameError = name => {
|
categoryNameError = name => {
|
||||||
/*
|
/*
|
||||||
return false if this is a LEGAL/acceptable category name,
|
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
||||||
or return an error type.
|
or return an error type.
|
||||||
*/
|
*/
|
||||||
|
if (!name) return false;
|
||||||
|
|
||||||
const { categoricalSelection } = this.props;
|
const { categoricalSelection } = this.props;
|
||||||
const allCategoryNames = Object.keys(categoricalSelection);
|
const allCategoryNames = Object.keys(categoricalSelection);
|
||||||
|
|
||||||
@@ -83,6 +85,7 @@ class Categories extends React.Component {
|
|||||||
|
|
||||||
categoryNameErrorMessage = name => {
|
categoryNameErrorMessage = name => {
|
||||||
const err = this.categoryNameError(name);
|
const err = this.categoryNameError(name);
|
||||||
|
if (err === false) return null;
|
||||||
if (err === "duplicate") {
|
if (err === "duplicate") {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
@@ -167,7 +170,6 @@ class Categories extends React.Component {
|
|||||||
autoFocus
|
autoFocus
|
||||||
value={newCategoryText}
|
value={newCategoryText}
|
||||||
intent={
|
intent={
|
||||||
newCategoryText &&
|
|
||||||
this.categoryNameError(newCategoryText)
|
this.categoryNameError(newCategoryText)
|
||||||
? "warning"
|
? "warning"
|
||||||
: "none"
|
: "none"
|
||||||
@@ -180,11 +182,9 @@ class Categories extends React.Component {
|
|||||||
<p
|
<p
|
||||||
style={{
|
style={{
|
||||||
marginTop: 7,
|
marginTop: 7,
|
||||||
visibility:
|
visibility: this.categoryNameError(newCategoryText)
|
||||||
newCategoryText &&
|
? "visible"
|
||||||
this.categoryNameError(newCategoryText)
|
: "hidden",
|
||||||
? "visible"
|
|
||||||
: "hidden",
|
|
||||||
color: Colors.ORANGE3
|
color: Colors.ORANGE3
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -227,7 +227,10 @@ class Categories extends React.Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
onClick={this.handleCreateUserAnno}
|
onClick={this.handleCreateUserAnno}
|
||||||
disabled={this.categoryNameError(newCategoryText)}
|
disabled={
|
||||||
|
!newCategoryText ||
|
||||||
|
this.categoryNameError(newCategoryText)
|
||||||
|
}
|
||||||
intent="primary"
|
intent="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class Category extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
isChecked: true,
|
isChecked: true,
|
||||||
isExpanded: false,
|
isExpanded: false,
|
||||||
newCategoryText: "",
|
newCategoryText: props.metadataField,
|
||||||
newLabelText: ""
|
newLabelText: ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -116,9 +116,19 @@ class Category extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleEditCategory = () => {
|
handleEditCategory = () => {
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField, categoricalSelection } = this.props;
|
||||||
const { newCategoryText } = this.state;
|
const { newCategoryText } = this.state;
|
||||||
|
|
||||||
|
const allCategoryNames = _.keys(categoricalSelection);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(allCategoryNames.indexOf(newCategoryText) > -1 &&
|
||||||
|
newCategoryText !== metadataField) ||
|
||||||
|
newCategoryText === ""
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: category edited",
|
type: "annotation: category edited",
|
||||||
metadataField,
|
metadataField,
|
||||||
@@ -145,26 +155,27 @@ class Category extends React.Component {
|
|||||||
|
|
||||||
labelNameError = name => {
|
labelNameError = name => {
|
||||||
/*
|
/*
|
||||||
return false if this is a LEGAL/acceptable category name,
|
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
||||||
or return an error type.
|
or return an error type.
|
||||||
*/
|
*/
|
||||||
const { metadataField, universe } = this.props;
|
let error = false;
|
||||||
const { obsByName } = universe.schema.annotations;
|
if (name) {
|
||||||
|
const { metadataField, universe } = this.props;
|
||||||
|
const { obsByName } = universe.schema.annotations;
|
||||||
|
|
||||||
if (obsByName[metadataField].categories.indexOf(name) !== -1) {
|
if (obsByName[metadataField].categories.indexOf(name) !== -1) {
|
||||||
return "duplicate";
|
error = "duplicate";
|
||||||
|
} else if (!AnnotationsHelpers.isLegalAnnotationName(name)) {
|
||||||
|
error = "characters";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return error;
|
||||||
if (!AnnotationsHelpers.isLegalAnnotationName(name)) {
|
|
||||||
return "characters";
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
labelNameErrorMessage = name => {
|
labelNameErrorMessage = name => {
|
||||||
const { metadataField } = this.props;
|
const { metadataField } = this.props;
|
||||||
const err = this.labelNameError(name);
|
const err = this.labelNameError(name);
|
||||||
|
if (err === false) return null;
|
||||||
if (err === "duplicate") {
|
if (err === "duplicate") {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
@@ -185,6 +196,83 @@ class Category extends React.Component {
|
|||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
categoryNameErrorMessage = () => {
|
||||||
|
const { newCategoryText } = this.state;
|
||||||
|
const err = this.editedCategoryNameError();
|
||||||
|
if (err === false) return null;
|
||||||
|
|
||||||
|
let markup = null;
|
||||||
|
|
||||||
|
if (err === "empty_string") {
|
||||||
|
markup = (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontStyle: "italic",
|
||||||
|
fontSize: 12,
|
||||||
|
marginTop: 5,
|
||||||
|
color: Colors.ORANGE3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{"Category name cannot be blank"}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (err === "already_exists") {
|
||||||
|
markup = (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontStyle: "italic",
|
||||||
|
fontSize: 12,
|
||||||
|
marginTop: 5,
|
||||||
|
color: Colors.ORANGE3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{"Category name must be unique"}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (err === "characters") {
|
||||||
|
markup = (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontStyle: "italic",
|
||||||
|
fontSize: 12,
|
||||||
|
marginTop: 5,
|
||||||
|
color: Colors.ORANGE3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{"Only alphanumeric and underscore allowed"}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return markup;
|
||||||
|
};
|
||||||
|
|
||||||
|
editedCategoryNameError = () => {
|
||||||
|
const { metadataField, categoricalSelection } = this.props;
|
||||||
|
const { newCategoryText } = this.state;
|
||||||
|
const allCategoryNames = _.keys(categoricalSelection);
|
||||||
|
|
||||||
|
const isEmptyString = newCategoryText === "";
|
||||||
|
const categoryNameAlreadyExists =
|
||||||
|
allCategoryNames.indexOf(newCategoryText) > -1;
|
||||||
|
const sameName = newCategoryText === metadataField;
|
||||||
|
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
if (isEmptyString) {
|
||||||
|
error = "empty_string";
|
||||||
|
} else if (categoryNameAlreadyExists && !sameName) {
|
||||||
|
error = "already_exists";
|
||||||
|
} else if (!AnnotationsHelpers.isLegalAnnotationName(newCategoryText)) {
|
||||||
|
error = "characters";
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
||||||
toggleAll() {
|
toggleAll() {
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -251,6 +339,7 @@ class Category extends React.Component {
|
|||||||
...cat.categoryValueIndices
|
...cat.categoryValueIndices
|
||||||
]);
|
]);
|
||||||
const optTuplesAsKey = _.map(optTuples, t => t[0]).join(""); // animation
|
const optTuplesAsKey = _.map(optTuples, t => t[0]).join(""); // animation
|
||||||
|
const allCategoryNames = _.keys(categoricalSelection);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -271,7 +360,7 @@ class Category extends React.Component {
|
|||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
alignItems: "baseline"
|
alignItems: "flex-start"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<label className="bp3-control bp3-checkbox">
|
<label className="bp3-control bp3-checkbox">
|
||||||
@@ -332,7 +421,7 @@ class Category extends React.Component {
|
|||||||
rightElement={
|
rightElement={
|
||||||
<Button
|
<Button
|
||||||
minimal
|
minimal
|
||||||
disabled={newCategoryText.length === 0}
|
disabled={this.editedCategoryNameError()}
|
||||||
style={{ position: "relative", top: -1 }}
|
style={{ position: "relative", top: -1 }}
|
||||||
type="button"
|
type="button"
|
||||||
icon="small-tick"
|
icon="small-tick"
|
||||||
@@ -342,6 +431,7 @@ class Category extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{this.categoryNameErrorMessage()}
|
||||||
</form>
|
</form>
|
||||||
) : (
|
) : (
|
||||||
metadataField
|
metadataField
|
||||||
@@ -385,10 +475,7 @@ class Category extends React.Component {
|
|||||||
autoFocus
|
autoFocus
|
||||||
value={newLabelText}
|
value={newLabelText}
|
||||||
intent={
|
intent={
|
||||||
// universe.schema.annotations.obsByName[
|
this.labelNameError(newLabelText)
|
||||||
// metadataField
|
|
||||||
// ].categories.indexOf(newLabelText) !== -1
|
|
||||||
newLabelText && this.labelNameError(newLabelText)
|
|
||||||
? "warning"
|
? "warning"
|
||||||
: "none"
|
: "none"
|
||||||
}
|
}
|
||||||
@@ -400,13 +487,9 @@ class Category extends React.Component {
|
|||||||
<p
|
<p
|
||||||
style={{
|
style={{
|
||||||
marginTop: 7,
|
marginTop: 7,
|
||||||
visibility:
|
visibility: this.labelNameError(newLabelText)
|
||||||
// universe.schema.annotations.obsByName[
|
? "visible"
|
||||||
// metadataField
|
: "hidden",
|
||||||
// ].categories.indexOf(newLabelText) !== -1
|
|
||||||
newLabelText && this.labelNameError(newLabelText)
|
|
||||||
? "visible"
|
|
||||||
: "hidden",
|
|
||||||
color: Colors.ORANGE3
|
color: Colors.ORANGE3
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -423,11 +506,7 @@ class Category extends React.Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
disabled={
|
disabled={
|
||||||
newLabelText.length === 0 ||
|
!newLabelText || this.labelNameError(newLabelText)
|
||||||
// universe.schema.annotations.obsByName[
|
|
||||||
// metadataField
|
|
||||||
// ].categories.indexOf(newLabelText) !== -1
|
|
||||||
this.labelNameError(newLabelText)
|
|
||||||
}
|
}
|
||||||
onClick={this.handleAddNewLabelToCategory}
|
onClick={this.handleAddNewLabelToCategory}
|
||||||
intent="primary"
|
intent="primary"
|
||||||
|
|||||||
@@ -31,19 +31,26 @@ class CategoryValue extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
editedLabelText: ""
|
editedLabelText: String(
|
||||||
|
props.categoricalSelection[props.metadataField].categoryValues[
|
||||||
|
props.categoryIndex
|
||||||
|
]
|
||||||
|
).valueOf()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteValue = () => {
|
getLabel = () => {
|
||||||
const {
|
const { metadataField, categoryIndex, categoricalSelection } = this.props;
|
||||||
dispatch,
|
|
||||||
metadataField,
|
|
||||||
categoryIndex,
|
|
||||||
categoricalSelection
|
|
||||||
} = this.props;
|
|
||||||
const category = categoricalSelection[metadataField];
|
const category = categoricalSelection[metadataField];
|
||||||
const label = category.categoryValues[categoryIndex];
|
const label = category.categoryValues[categoryIndex];
|
||||||
|
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleDeleteValue = () => {
|
||||||
|
const { dispatch, metadataField } = this.props;
|
||||||
|
const label = this.getLabel();
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: delete label",
|
type: "annotation: delete label",
|
||||||
metadataField,
|
metadataField,
|
||||||
@@ -52,14 +59,8 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleAddCurrentSelectionToThisLabel = () => {
|
handleAddCurrentSelectionToThisLabel = () => {
|
||||||
const {
|
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||||
dispatch,
|
const label = this.getLabel();
|
||||||
metadataField,
|
|
||||||
categoryIndex,
|
|
||||||
categoricalSelection
|
|
||||||
} = this.props;
|
|
||||||
const category = categoricalSelection[metadataField];
|
|
||||||
const label = category.categoryValues[categoryIndex];
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: label current cell selection",
|
type: "annotation: label current cell selection",
|
||||||
metadataField,
|
metadataField,
|
||||||
@@ -69,15 +70,9 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleEditValue = () => {
|
handleEditValue = () => {
|
||||||
const {
|
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||||
dispatch,
|
|
||||||
metadataField,
|
|
||||||
categoryIndex,
|
|
||||||
categoricalSelection
|
|
||||||
} = this.props;
|
|
||||||
const { editedLabelText } = this.state;
|
const { editedLabelText } = this.state;
|
||||||
const category = categoricalSelection[metadataField];
|
const label = this.getLabel();
|
||||||
const label = category.categoryValues[categoryIndex];
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: label edited",
|
type: "annotation: label edited",
|
||||||
editedLabel: editedLabelText,
|
editedLabel: editedLabelText,
|
||||||
@@ -85,7 +80,80 @@ class CategoryValue extends React.Component {
|
|||||||
categoryIndex,
|
categoryIndex,
|
||||||
label
|
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 = () => {
|
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:
|
Checks to see if at least one of the following changed:
|
||||||
* world state
|
* world state
|
||||||
@@ -125,7 +193,7 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
If and only if true, update the component
|
If and only if true, update the component
|
||||||
*/
|
*/
|
||||||
const { props } = this;
|
const { props, state } = this;
|
||||||
const { metadataField, categoryIndex, categoricalSelection } = props;
|
const { metadataField, categoryIndex, categoricalSelection } = props;
|
||||||
const { categoricalSelection: newCategoricalSelection } = nextProps;
|
const { categoricalSelection: newCategoricalSelection } = nextProps;
|
||||||
|
|
||||||
@@ -141,13 +209,15 @@ class CategoryValue extends React.Component {
|
|||||||
const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor;
|
const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor;
|
||||||
const annotationsChange = props.annotations !== nextProps.annotations;
|
const annotationsChange = props.annotations !== nextProps.annotations;
|
||||||
const crossfilterChange = props.crossfilter !== nextProps.crossfilter;
|
const crossfilterChange = props.crossfilter !== nextProps.crossfilter;
|
||||||
|
const editingLabel = state.editedLabelText !== nextState.editedLabelText;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
valueSelectionChange ||
|
valueSelectionChange ||
|
||||||
worldChange ||
|
worldChange ||
|
||||||
colorAccessorChange ||
|
colorAccessorChange ||
|
||||||
annotationsChange ||
|
annotationsChange ||
|
||||||
crossfilterChange
|
crossfilterChange ||
|
||||||
|
editingLabel
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -222,6 +292,8 @@ class CategoryValue extends React.Component {
|
|||||||
flippedProps
|
flippedProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const { editedLabelText } = this.state;
|
||||||
|
|
||||||
if (!categoricalSelection) return null;
|
if (!categoricalSelection) return null;
|
||||||
|
|
||||||
const category = categoricalSelection[metadataField];
|
const category = categoricalSelection[metadataField];
|
||||||
@@ -347,6 +419,9 @@ class CategoryValue extends React.Component {
|
|||||||
<form
|
<form
|
||||||
onSubmit={e => {
|
onSubmit={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (this.valueNameError()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.handleEditValue();
|
this.handleEditValue();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -357,6 +432,7 @@ class CategoryValue extends React.Component {
|
|||||||
}}
|
}}
|
||||||
small
|
small
|
||||||
autoFocus
|
autoFocus
|
||||||
|
intent={this.valueNameError() ? "warning" : "none"}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.setState({ editedLabelText: e.target.value });
|
this.setState({ editedLabelText: e.target.value });
|
||||||
}}
|
}}
|
||||||
@@ -365,6 +441,7 @@ class CategoryValue extends React.Component {
|
|||||||
<Button
|
<Button
|
||||||
minimal
|
minimal
|
||||||
style={{ position: "relative", top: -1 }}
|
style={{ position: "relative", top: -1 }}
|
||||||
|
disabled={this.valueNameError()}
|
||||||
type="button"
|
type="button"
|
||||||
icon="small-tick"
|
icon="small-tick"
|
||||||
data-testclass="submitEdit"
|
data-testclass="submitEdit"
|
||||||
@@ -373,6 +450,7 @@ class CategoryValue extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{this.valueNameErrorMessage()}
|
||||||
</form>
|
</form>
|
||||||
) : null}
|
) : null}
|
||||||
{/*
|
{/*
|
||||||
|
|||||||
Reference in New Issue
Block a user