mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-30 03:08:12 +08:00
refactor categorical controls state (#1549)
* refactor categorical controls state * lint * fix race condition in tests * fix typo * add missing update on subset * remove obsolete code * update jest and puppeteer major version; update all minors * update when label changes * remove lint from tests; increase timeouts in e2e tests * changes in response to PR review * lint * more PR comment changes * more PR comment fixes * lint * more PR comment resolutions
This commit is contained in:
@@ -1,13 +1,6 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Button, Tooltip, Dialog, Classes, Colors } from "@blueprintjs/core";
|
||||
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe,
|
||||
}))
|
||||
class AnnoDialog extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Button, MenuItem } from "@blueprintjs/core";
|
||||
import { Select } from "@blueprintjs/select";
|
||||
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe,
|
||||
}))
|
||||
class DuplicateCategorySelect extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -5,8 +5,6 @@ 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,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import AnnoDialog from "../annoDialog";
|
||||
import LabelInput from "../labelInput";
|
||||
@@ -8,9 +7,9 @@ import { labelPrompt } from "../labelUtil";
|
||||
import { AnnotationsHelpers } from "../../../util/stateManager";
|
||||
|
||||
@connect((state) => ({
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe,
|
||||
schema: state.world?.schema,
|
||||
ontology: state.ontology,
|
||||
}))
|
||||
class AnnoDialogEditCategoryName extends React.PureComponent {
|
||||
@@ -36,11 +35,14 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
||||
};
|
||||
|
||||
handleEditCategory = (e) => {
|
||||
const { dispatch, metadataField, categoricalSelection } = this.props;
|
||||
const { dispatch, metadataField } = this.props;
|
||||
const { newCategoryText } = this.state;
|
||||
|
||||
const allCategoryNames = _.keys(categoricalSelection);
|
||||
|
||||
/*
|
||||
test for uniqueness against *all* annotation names, not just the subset
|
||||
we render as categorical.
|
||||
*/
|
||||
const allCategoryNames = this.allCategoryNames();
|
||||
if (
|
||||
(allCategoryNames.indexOf(newCategoryText) > -1 &&
|
||||
newCategoryText !== metadataField) ||
|
||||
@@ -60,7 +62,7 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
||||
};
|
||||
|
||||
editedCategoryNameError = (name) => {
|
||||
const { metadataField, categoricalSelection } = this.props;
|
||||
const { metadataField } = this.props;
|
||||
|
||||
/* check for syntax errors in category name */
|
||||
const error = AnnotationsHelpers.annotationNameIsErroneous(name);
|
||||
@@ -69,7 +71,12 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
||||
}
|
||||
|
||||
/* check for duplicative categories */
|
||||
const allCategoryNames = _.keys(categoricalSelection);
|
||||
|
||||
/*
|
||||
test for uniqueness against *all* annotation names, not just the subset
|
||||
we render as categorical.
|
||||
*/
|
||||
const allCategoryNames = this.allCategoryNames();
|
||||
const categoryNameAlreadyExists = allCategoryNames.indexOf(name) > -1;
|
||||
const sameName = name === metadataField;
|
||||
if (categoryNameAlreadyExists && !sameName) {
|
||||
@@ -88,6 +95,11 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
||||
);
|
||||
};
|
||||
|
||||
allCategoryNames() {
|
||||
const { schema } = this.props;
|
||||
return schema.annotations.obs.columns.map((c) => c.name);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { newCategoryText } = this.state;
|
||||
const { metadataField, annotations, ontology } = this.props;
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import { Flipper, Flipped } from "react-flip-toolkit";
|
||||
|
||||
import * as globals from "../../../globals";
|
||||
import Value from "../value";
|
||||
|
||||
@connect((state) => ({
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
}))
|
||||
class Category extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -16,9 +11,9 @@ class Category extends React.Component {
|
||||
}
|
||||
|
||||
renderCategoryItems(optTuples) {
|
||||
const { metadataField, isUserAnno } = this.props;
|
||||
const { metadataField, isUserAnno, categorySummary } = this.props;
|
||||
|
||||
return _.map(optTuples, (tuple, i) => {
|
||||
return optTuples.map((tuple, i) => {
|
||||
return (
|
||||
<Flipped key={tuple[1]} flipId={tuple[1]}>
|
||||
{(flippedProps) => (
|
||||
@@ -30,6 +25,7 @@ class Category extends React.Component {
|
||||
categoryIndex={tuple[1]}
|
||||
i={i}
|
||||
flippedProps={flippedProps}
|
||||
categorySummary={categorySummary}
|
||||
/>
|
||||
)}
|
||||
</Flipped>
|
||||
@@ -38,16 +34,10 @@ class Category extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
metadataField,
|
||||
categoricalSelection,
|
||||
children,
|
||||
isExpanded,
|
||||
} = this.props;
|
||||
const { isTruncated } = categoricalSelection[metadataField];
|
||||
const cat = categoricalSelection[metadataField];
|
||||
const optTuples = [...cat.categoryValueIndices];
|
||||
const optTuplesAsKey = _.map(optTuples, (t) => t[0]).join(""); // animation
|
||||
const { metadataField, categorySummary, children, isExpanded } = this.props;
|
||||
const { isTruncated } = categorySummary;
|
||||
const optTuples = [...categorySummary.categoryValueIndices];
|
||||
const optTuplesAsKey = optTuples.map((t) => t[0]).join(""); // animation
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import { FaChevronRight, FaChevronDown } from "react-icons/fa";
|
||||
import { AnchorButton, Button, Tooltip } from "@blueprintjs/core";
|
||||
@@ -10,6 +9,7 @@ import AnnoDialogAddLabel from "./annoDialogAddLabel";
|
||||
import Truncate from "../../util/truncate";
|
||||
|
||||
import * as globals from "../../../globals";
|
||||
import { createCategorySummary as _createCategorySummary } from "../../../util/stateManager/controlsHelpers";
|
||||
|
||||
const LABEL_WIDTH = globals.leftSidebarWidth - 100;
|
||||
const ANNO_BUTTON_WIDTH = 50;
|
||||
@@ -22,6 +22,7 @@ const LABEL_WIDTH_ANNO = LABEL_WIDTH - ANNO_BUTTON_WIDTH;
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe,
|
||||
world: state.world,
|
||||
schema: state.world?.schema,
|
||||
};
|
||||
})
|
||||
@@ -30,37 +31,50 @@ class Category extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
isChecked: true,
|
||||
categorySummary: this.createCategorySummary(),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { categoricalSelection, metadataField } = this.props;
|
||||
const { categoricalSelection, metadataField, world } = this.props;
|
||||
let { categorySummary } = this.state;
|
||||
|
||||
if (
|
||||
world !== prevProps.world ||
|
||||
metadataField !== prevProps.metadataField ||
|
||||
!categorySummary
|
||||
) {
|
||||
const newCategorySummary = this.createCategorySummary();
|
||||
if (categorySummary !== newCategorySummary) {
|
||||
categorySummary = newCategorySummary;
|
||||
/* eslint-disable-next-line react/no-did-update-set-state -- Contained in if statement to prevent infinite looping */
|
||||
this.setState({ categorySummary });
|
||||
}
|
||||
}
|
||||
|
||||
const cat = categoricalSelection?.[metadataField];
|
||||
if (
|
||||
categoricalSelection !== prevProps.categoricalSelection &&
|
||||
!!cat &&
|
||||
!!this.checkbox
|
||||
) {
|
||||
const categoryCount = {
|
||||
// total number of categories in this dimension
|
||||
totalCatCount: cat.numCategoryValues,
|
||||
// number of selected options in this category
|
||||
selectedCatCount: _.reduce(
|
||||
cat.categoryValueSelected,
|
||||
(res, cond) => (cond ? res + 1 : res),
|
||||
0
|
||||
),
|
||||
};
|
||||
// total number of categories in this dimension
|
||||
const totalCatCount = categorySummary.numCategoryValues;
|
||||
// number of selected options in this category
|
||||
const selectedCatCount = categorySummary.categoryValues.reduce(
|
||||
(res, label) => (cat.get(label) ?? true ? res + 1 : res),
|
||||
0
|
||||
);
|
||||
/* eslint-disable react/no-did-update-set-state -- Contained in if statement to prevent infinite looping */
|
||||
if (categoryCount.selectedCatCount === categoryCount.totalCatCount) {
|
||||
if (selectedCatCount === totalCatCount) {
|
||||
/* everything is on, so not indeterminate */
|
||||
this.checkbox.indeterminate = false;
|
||||
this.setState({ isChecked: true });
|
||||
} else if (categoryCount.selectedCatCount === 0) {
|
||||
} else if (selectedCatCount === 0) {
|
||||
/* nothing is on, so no */
|
||||
this.checkbox.indeterminate = false;
|
||||
this.setState({ isChecked: false });
|
||||
} else if (categoryCount.selectedCatCount < categoryCount.totalCatCount) {
|
||||
} else if (selectedCatCount < totalCatCount) {
|
||||
/* to be explicit... */
|
||||
this.checkbox.indeterminate = true;
|
||||
this.setState({ isChecked: false });
|
||||
@@ -87,27 +101,37 @@ class Category extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
createCategorySummary() {
|
||||
const { world, metadataField } = this.props;
|
||||
if (!world || !metadataField || !world.obsAnnotations.hasCol(metadataField))
|
||||
return null;
|
||||
return _createCategorySummary(world, metadataField);
|
||||
}
|
||||
|
||||
toggleNone() {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
const { categorySummary } = this.state;
|
||||
dispatch({
|
||||
type: "categorical metadata filter none of these",
|
||||
metadataField,
|
||||
labels: categorySummary.categoryValues,
|
||||
});
|
||||
this.setState({ isChecked: false });
|
||||
}
|
||||
|
||||
toggleAll() {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
const { categorySummary } = this.state;
|
||||
dispatch({
|
||||
type: "categorical metadata filter all of these",
|
||||
metadataField,
|
||||
labels: categorySummary.categoryValues,
|
||||
});
|
||||
this.setState({ isChecked: true });
|
||||
}
|
||||
|
||||
handleToggleAllClick() {
|
||||
const { isChecked } = this.state;
|
||||
// || this.checkbox.indeterminate === false
|
||||
if (isChecked) {
|
||||
this.toggleNone();
|
||||
} else {
|
||||
@@ -168,29 +192,19 @@ class Category extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isChecked } = this.state;
|
||||
const {
|
||||
metadataField,
|
||||
categoricalSelection,
|
||||
isColorAccessor,
|
||||
isExpanded,
|
||||
schema,
|
||||
} = this.props;
|
||||
const { isChecked, categorySummary } = this.state;
|
||||
const { metadataField, isColorAccessor, isExpanded, schema } = this.props;
|
||||
|
||||
const isStillLoading = !(categoricalSelection?.[metadataField] ?? false);
|
||||
const isStillLoading = !categorySummary;
|
||||
if (isStillLoading) {
|
||||
return this.renderIsStillLoading();
|
||||
}
|
||||
|
||||
const checkboxID = `category-select-${metadataField}`;
|
||||
|
||||
const isUserAnno =
|
||||
schema?.annotations?.obsByName[metadataField]?.writable ?? false;
|
||||
const isTruncated = _.get(
|
||||
categoricalSelection,
|
||||
[metadataField, "isTruncated"],
|
||||
false
|
||||
);
|
||||
const isUserAnno = !!schema?.annotations?.obsByName[metadataField]
|
||||
?.writable;
|
||||
const isTruncated = !!categorySummary?.isTruncated;
|
||||
|
||||
if (
|
||||
!isUserAnno &&
|
||||
@@ -217,6 +231,7 @@ class Category extends React.Component {
|
||||
metadataField={metadataField}
|
||||
isExpanded={isExpanded}
|
||||
isUserAnno={isUserAnno}
|
||||
categorySummary={categorySummary}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -13,7 +13,6 @@ import { labelPrompt } from "./labelUtil";
|
||||
@connect((state) => ({
|
||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
||||
schema: state.world?.schema,
|
||||
config: state.config,
|
||||
ontology: state.ontology,
|
||||
}))
|
||||
class Categories extends React.Component {
|
||||
@@ -126,12 +125,11 @@ class Categories extends React.Component {
|
||||
newCategoryText,
|
||||
expandedCats,
|
||||
} = this.state;
|
||||
const { writableCategoriesEnabled, schema, config, ontology } = this.props;
|
||||
const { writableCategoriesEnabled, schema, ontology } = this.props;
|
||||
const ontologyEnabled = ontology?.enabled ?? false;
|
||||
/* all names, sorted in display order. Will be rendered in this order */
|
||||
const allCategoryNames = ControlsHelpers.selectableCategoryNames(
|
||||
schema,
|
||||
ControlsHelpers.maxCategoryItems(config)
|
||||
schema
|
||||
).sort();
|
||||
|
||||
return (
|
||||
|
||||
@@ -21,11 +21,11 @@ import { AnnotationsHelpers } from "../../../util/stateManager";
|
||||
import { labelPrompt, isLabelErroneous } from "../labelUtil";
|
||||
|
||||
/* this is defined outside of the class so we can use it in connect() */
|
||||
function _currentLabel(ownProps, categoricalSelection) {
|
||||
const { metadataField, categoryIndex } = ownProps;
|
||||
return String(
|
||||
categoricalSelection[metadataField].categoryValues[categoryIndex]
|
||||
).valueOf();
|
||||
function _currentLabelAsString(ownProps) {
|
||||
const { categorySummary, categoryIndex } = ownProps;
|
||||
// when called as a function, the String() constructor performs type conversion,
|
||||
// and returns a primtive string.
|
||||
return String(categorySummary.categoryValues[categoryIndex]);
|
||||
}
|
||||
|
||||
@connect((state, ownProps) => {
|
||||
@@ -33,8 +33,7 @@ function _currentLabel(ownProps, categoricalSelection) {
|
||||
const { metadataField } = ownProps;
|
||||
const isDilated =
|
||||
pointDilation.metadataField === metadataField &&
|
||||
pointDilation.categoryField ===
|
||||
_currentLabel(ownProps, categoricalSelection);
|
||||
pointDilation.categoryField === _currentLabelAsString(ownProps);
|
||||
return {
|
||||
categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
@@ -51,28 +50,39 @@ class CategoryValue extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editedLabelText: this.currentLabel(),
|
||||
editedLabelText: this.currentLabelAsString(),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { categoricalSelection, metadataField, categoryIndex } = this.props;
|
||||
const {
|
||||
categoricalSelection,
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
categorySummary,
|
||||
} = this.props;
|
||||
if (
|
||||
prevProps.categoricalSelection !== categoricalSelection ||
|
||||
prevProps.metadataField !== metadataField ||
|
||||
prevProps.categoryIndex !== categoryIndex
|
||||
prevProps.categoryIndex !== categoryIndex ||
|
||||
prevProps.categorySummary !== categorySummary
|
||||
) {
|
||||
// eslint-disable-next-line react/no-did-update-set-state --- adequately checked to prevent looping
|
||||
this.setState({
|
||||
editedLabelText: this.currentLabel(),
|
||||
editedLabelText: this.currentLabelAsString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getLabel() {
|
||||
const { categoryIndex, categorySummary } = this.props;
|
||||
const label = categorySummary.categoryValues[categoryIndex];
|
||||
return label;
|
||||
}
|
||||
|
||||
handleDeleteValue = () => {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
const label = this.getLabel();
|
||||
|
||||
dispatch({
|
||||
type: "annotation: delete label",
|
||||
metadataField,
|
||||
@@ -121,7 +131,7 @@ class CategoryValue extends React.Component {
|
||||
|
||||
labelNameError = (name) => {
|
||||
const { metadataField, ontology, schema } = this.props;
|
||||
if (name === this.currentLabel()) return false;
|
||||
if (name === this.currentLabelAsString()) return false;
|
||||
return isLabelErroneous(name, metadataField, ontology, schema);
|
||||
};
|
||||
|
||||
@@ -131,31 +141,44 @@ class CategoryValue extends React.Component {
|
||||
|
||||
activateEditLabelMode = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const label = this.getLabel();
|
||||
dispatch({
|
||||
type: "annotation: activate edit label mode",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
cancelEditMode = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const label = this.getLabel();
|
||||
this.setState({
|
||||
editedLabelText: this.currentLabel(),
|
||||
editedLabelText: this.currentLabelAsString(),
|
||||
});
|
||||
dispatch({
|
||||
type: "annotation: cancel edit label mode",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
toggleOff = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const {
|
||||
dispatch,
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
categorySummary,
|
||||
} = this.props;
|
||||
const labels = categorySummary.categoryValues;
|
||||
const label = labels[categoryIndex];
|
||||
dispatch({
|
||||
type: "categorical metadata filter deselect",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
labels,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -170,16 +193,24 @@ class CategoryValue extends React.Component {
|
||||
If and only if true, update the component
|
||||
*/
|
||||
const { props, state } = this;
|
||||
const { metadataField, categoryIndex, categoricalSelection } = props;
|
||||
const { categoricalSelection: newCategoricalSelection } = nextProps;
|
||||
const {
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
categoricalSelection,
|
||||
categorySummary,
|
||||
} = props;
|
||||
const {
|
||||
categoryIndex: newCategoryIndex,
|
||||
categoricalSelection: newCategoricalSelection,
|
||||
categorySummary: newCategorySummary,
|
||||
} = nextProps;
|
||||
|
||||
const label = categorySummary.categoryValues[categoryIndex];
|
||||
const newLabel = newCategorySummary.categoryValues[newCategoryIndex];
|
||||
const labelChanged = label !== newLabel;
|
||||
const valueSelectionChange =
|
||||
categoricalSelection[metadataField].categoryValueSelected[
|
||||
categoryIndex
|
||||
] !==
|
||||
newCategoricalSelection[metadataField].categoryValueSelected[
|
||||
categoryIndex
|
||||
];
|
||||
categoricalSelection[metadataField].get(label) !==
|
||||
newCategoricalSelection[metadataField].get(newLabel);
|
||||
|
||||
const worldChange = props.world !== nextProps.world;
|
||||
const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor;
|
||||
@@ -189,41 +220,60 @@ class CategoryValue extends React.Component {
|
||||
const editingLabel = state.editedLabelText !== nextState.editedLabelText;
|
||||
const dilationChange = props.isDilated !== nextProps.isDilated;
|
||||
|
||||
const count = categorySummary.categoryValueCounts[categoryIndex];
|
||||
const newCount = newCategorySummary.categoryValueCounts[newCategoryIndex];
|
||||
const countChanged = count !== newCount;
|
||||
|
||||
return (
|
||||
labelChanged ||
|
||||
valueSelectionChange ||
|
||||
worldChange ||
|
||||
colorAccessorChange ||
|
||||
annotationsChange ||
|
||||
crossfilterChange ||
|
||||
editingLabel ||
|
||||
dilationChange
|
||||
dilationChange ||
|
||||
countChanged
|
||||
);
|
||||
};
|
||||
|
||||
toggleOn = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const {
|
||||
dispatch,
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
categorySummary,
|
||||
} = this.props;
|
||||
const labels = categorySummary.categoryValues;
|
||||
const label = labels[categoryIndex];
|
||||
dispatch({
|
||||
type: "categorical metadata filter select",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
labels,
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseEnter = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const label = this.getLabel();
|
||||
dispatch({
|
||||
type: "category value mouse hover start",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseExit = () => {
|
||||
const { dispatch, metadataField, categoryIndex } = this.props;
|
||||
const label = this.getLabel();
|
||||
dispatch({
|
||||
type: "category value mouse hover end",
|
||||
metadataField,
|
||||
categoryIndex,
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -236,17 +286,8 @@ class CategoryValue extends React.Component {
|
||||
this.setState({ editedLabelText: e.target });
|
||||
};
|
||||
|
||||
getLabel = () => {
|
||||
const { metadataField, categoryIndex, categoricalSelection } = this.props;
|
||||
const category = categoricalSelection[metadataField];
|
||||
const label = category.categoryValues[categoryIndex];
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
currentLabel() {
|
||||
const { categoricalSelection } = this.props;
|
||||
return _currentLabel(this.props, categoricalSelection);
|
||||
currentLabelAsString() {
|
||||
return _currentLabelAsString(this.props);
|
||||
}
|
||||
|
||||
isAddCurrentSelectionDisabled(category, value) {
|
||||
@@ -294,6 +335,7 @@ class CategoryValue extends React.Component {
|
||||
flippedProps,
|
||||
isDilated,
|
||||
world,
|
||||
categorySummary,
|
||||
} = this.props;
|
||||
const ontologyEnabled = ontology?.enabled ?? false;
|
||||
|
||||
@@ -302,10 +344,10 @@ class CategoryValue extends React.Component {
|
||||
if (!categoricalSelection) return null;
|
||||
|
||||
const category = categoricalSelection[metadataField];
|
||||
const selected = category.categoryValueSelected[categoryIndex];
|
||||
const count = category.categoryValueCounts[categoryIndex];
|
||||
const value = category.categoryValues[categoryIndex];
|
||||
const displayString = this.currentLabel();
|
||||
const selected = category.get(this.getLabel()) ?? true;
|
||||
const count = categorySummary.categoryValueCounts[categoryIndex];
|
||||
const value = categorySummary.categoryValues[categoryIndex];
|
||||
const displayString = this.currentLabelAsString();
|
||||
|
||||
/* this is the color scale, so add swatches below */
|
||||
const isColorBy = metadataField === colorAccessor;
|
||||
|
||||
@@ -40,10 +40,7 @@ class CentroidLabels extends PureComponent {
|
||||
if (!colorAccessor || labels.size === undefined || labels.size === 0)
|
||||
return null;
|
||||
|
||||
const {
|
||||
categoryValueIndices,
|
||||
categoryValueSelected,
|
||||
} = categoricalSelection?.[colorAccessor];
|
||||
const category = categoricalSelection[colorAccessor];
|
||||
|
||||
const labelSVGS = [];
|
||||
let fontSize = "15px";
|
||||
@@ -57,7 +54,7 @@ class CentroidLabels extends PureComponent {
|
||||
fontWeight = "800";
|
||||
}
|
||||
|
||||
const selected = categoryValueSelected[categoryValueIndices.get(label)];
|
||||
const selected = category.get(label) ?? true;
|
||||
|
||||
// Mirror LSB middle truncation
|
||||
let displayLabel = label;
|
||||
|
||||
Reference in New Issue
Block a user