diff --git a/client/src/components/categorical/categorical.js b/client/src/components/categorical/categorical.js index 61f77728..3987b239 100644 --- a/client/src/components/categorical/categorical.js +++ b/client/src/components/categorical/categorical.js @@ -10,11 +10,11 @@ import AnnoSelect from "./annoSelect"; import LabelInput from "./labelInput"; import { labelPrompt } from "./labelUtil"; -@connect(state => ({ +@connect((state) => ({ writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false, schema: state.world?.schema, config: state.config, - ontology: state.ontology + ontology: state.ontology, })) class Categories extends React.Component { constructor(props) { @@ -23,22 +23,22 @@ class Categories extends React.Component { createAnnoModeActive: false, newCategoryText: "", categoryToDuplicate: null, - expandedCats: new Set() + expandedCats: new Set(), }; } - handleCreateUserAnno = e => { + handleCreateUserAnno = (e) => { const { dispatch } = this.props; const { newCategoryText, categoryToDuplicate } = this.state; dispatch({ type: "annotation: create category", data: newCategoryText, - categoryToDuplicate + categoryToDuplicate, }); this.setState({ createAnnoModeActive: false, categoryToDuplicate: null, - newCategoryText: "" + newCategoryText: "", }); e.preventDefault(); }; @@ -51,15 +51,15 @@ class Categories extends React.Component { this.setState({ createAnnoModeActive: false, categoryToDuplicate: null, - newCategoryText: "" + newCategoryText: "", }); }; - handleModalDuplicateCategorySelection = d => { + handleModalDuplicateCategorySelection = (d) => { this.setState({ categoryToDuplicate: d }); }; - categoryNameError = name => { + categoryNameError = (name) => { /* return false if this is a LEGAL/acceptable category name or NULL/empty string, or return an error type. @@ -73,7 +73,7 @@ class Categories extends React.Component { we render as categorical. */ const { schema } = this.props; - const allCategoryNames = schema.annotations.obs.columns.map(c => c.name); + const allCategoryNames = schema.annotations.obs.columns.map((c) => c.name); /* check category name syntax */ const error = AnnotationsHelpers.annotationNameIsErroneous(name); @@ -90,15 +90,15 @@ class Categories extends React.Component { return false; }; - handleChange = name => { + handleChange = (name) => { this.setState({ newCategoryText: name }); }; - handleSelect = name => { + handleSelect = (name) => { this.setState({ newCategoryText: name }); }; - instruction = name => { + instruction = (name) => { return labelPrompt( this.categoryNameError(name), "New, unique category name", @@ -106,25 +106,76 @@ class Categories extends React.Component { ); }; - onExpansionChange = catName => { - const {expandedCats} = this.state; + onExpansionChange = (catName) => { + const { expandedCats } = this.state; if (expandedCats.has(catName)) { const _expandedCats = new Set(expandedCats); - _expandedCats.delete(catName) - this.setState({expandedCats: _expandedCats}) + _expandedCats.delete(catName); + this.setState({ expandedCats: _expandedCats }); } else { const _expandedCats = new Set(expandedCats); - _expandedCats.add(catName) - this.setState({expandedCats: _expandedCats}) + _expandedCats.add(catName); + this.setState({ expandedCats: _expandedCats }); } - } + }; + + maybeRenderSingleLabel = (allCategoryNames, schema) => { + return allCategoryNames.map((catName) => + !schema.annotations.obsByName[catName].writable && + schema.annotations.obsByName[catName].categories.length === 1 ? ( +
+ {catName}:{" "} + {schema.annotations.obsByName[catName].categories[0]} +
+ ) : null + ); + }; + maybeRenderReadOnly = ( + allCategoryNames, + schema, + expandedCats, + createAnnoModeActive + ) => { + return allCategoryNames.map((catName) => + !schema.annotations.obsByName[catName].writable && + schema.annotations.obsByName[catName].categories.length > 1 ? ( + + ) : null + ); + }; + maybeRenderAnnotations = ( + allCategoryNames, + schema, + expandedCats, + createAnnoModeActive + ) => { + return allCategoryNames.map((catName) => + schema.annotations.obsByName[catName].writable ? ( + + ) : null + ); + }; render() { const { createAnnoModeActive, categoryToDuplicate, newCategoryText, - expandedCats + expandedCats, } = this.state; const { writableCategoriesEnabled, schema, config, ontology } = this.props; const ontologyEnabled = ontology?.enabled ?? false; @@ -137,7 +188,7 @@ class Categories extends React.Component { return (
@@ -176,33 +227,33 @@ class Categories extends React.Component { } /> - {/* READ ONLY CATEGORICAL FIELDS */} - {/* this is duplicative but flat, could be abstracted */} - {allCategoryNames.map(catName => - !schema.annotations.obsByName[catName].writable ? ( - - ) : null - )} - {/* WRITEABLE FIELDS */} - {allCategoryNames.map(catName => - schema.annotations.obsByName[catName].writable ? ( - - ) : null - )} +
+ { + this.maybeRenderSingleLabel( + allCategoryNames, + schema, + expandedCats, + createAnnoModeActive + ) /* Categories with only one label */ + } +
+ { + this.maybeRenderReadOnly( + allCategoryNames, + schema, + expandedCats, + createAnnoModeActive + ) /* Read only categorical fields, ostensibly 'normal' mode */ + } + { + this.maybeRenderAnnotations( + allCategoryNames, + schema, + expandedCats, + createAnnoModeActive + ) /* Writable fields, ie., anno */ + } + {writableCategoriesEnabled ? (