Merge branch 'master' into colinmegill/geneset-prototype

This commit is contained in:
Colin Megill
2020-05-19 15:58:36 -04:00
47 changed files with 314 additions and 294 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ import {
doBinaryRequest,
dispatchNetworkErrorMessageToUser,
} from "../util/actionHelpers";
import { PromiseLimit } from "../util/promiseLimit";
import PromiseLimit from "../util/promiseLimit";
import { requestReembed, reembedResetWorldToUniverse } from "./reembed";
import { loadUserColorConfig } from "../util/stateManager/colorHelpers";
@@ -18,7 +18,7 @@ import {
saveInProgress: state.autosave?.saveInProgress ?? false,
lastSavedObsAnnotations: state.autosave?.lastSavedObsAnnotations,
error: state.autosave?.error,
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false,
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
}))
class FilenameDialog extends React.Component {
constructor(props) {
+1 -2
View File
@@ -1,6 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import * as globals from "../../globals";
import actions from "../../actions";
import FilenameDialog from "./filenameDialog";
@@ -11,7 +10,7 @@ import FilenameDialog from "./filenameDialog";
saveInProgress: state.autosave?.saveInProgress ?? false,
lastSavedObsAnnotations: state.autosave?.lastSavedObsAnnotations,
error: state.autosave?.error,
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false,
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
initialDataLoadComplete: state.autosave?.initialDataLoadComplete,
}))
class Autosave extends React.Component {
@@ -64,7 +64,7 @@ class Category extends React.Component {
} else if (categoryCount.selectedCatCount < categoryCount.totalCatCount) {
/* to be explicit... */
this.checkbox.indeterminate = true;
this.setState({ isChecked: false });
this.setState({ isChecked: false }); // eslint-disable-line react/no-did-update-set-state
}
}
}
@@ -77,14 +77,15 @@ class Category extends React.Component {
});
};
toggleAll() {
const { dispatch, metadataField } = this.props;
dispatch({
type: "categorical metadata filter all of these",
metadataField,
});
this.setState({ isChecked: true });
}
handleCategoryClick = () => {
const { annotations, metadataField, onExpansionChange } = this.props;
const editingCategory =
annotations.isEditingCategoryName &&
annotations.categoryBeingEdited === metadataField;
if (!editingCategory) {
onExpansionChange(metadataField);
}
};
toggleNone() {
const { dispatch, metadataField } = this.props;
@@ -95,6 +96,15 @@ class Category extends React.Component {
this.setState({ isChecked: false });
}
toggleAll() {
const { dispatch, metadataField } = this.props;
dispatch({
type: "categorical metadata filter all of these",
metadataField,
});
this.setState({ isChecked: true });
}
handleToggleAllClick() {
const { isChecked } = this.state;
// || this.checkbox.indeterminate === false
@@ -115,6 +125,8 @@ class Category extends React.Component {
globals.categoryDisplayStringMaxLength
);
const checkboxID = `category-select-${metadataField}`;
return (
<div
style={{
@@ -135,8 +147,8 @@ class Category extends React.Component {
alignItems: "flex-start",
}}
>
<label className="bp3-control bp3-checkbox">
<input disabled checked type="checkbox" />
<label htmlFor={checkboxID} className="bp3-control bp3-checkbox">
<input disabled id={checkboxID} checked type="checkbox" />
<span className="bp3-control-indicator" />
</label>
<Tooltip
@@ -174,9 +186,7 @@ class Category extends React.Component {
metadataField,
categoricalSelection,
isColorAccessor,
annotations,
isExpanded,
onExpansionChange,
schema,
} = this.props;
@@ -185,6 +195,8 @@ class Category extends React.Component {
return this.renderIsStillLoading();
}
const checkboxID = `category-select-${metadataField}`;
const isUserAnno =
schema?.annotations?.obsByName[metadataField]?.writable ?? false;
const isTruncated = _.get(
@@ -225,8 +237,9 @@ class Category extends React.Component {
alignItems: "flex-start",
}}
>
<label className="bp3-control bp3-checkbox">
<label className="bp3-control bp3-checkbox" htmlFor={checkboxID}>
<input
id={checkboxID}
data-testclass="category-select"
data-testid={`${metadataField}:category-select`}
onChange={this.handleToggleAllClick.bind(this)}
@@ -251,19 +264,19 @@ class Category extends React.Component {
}}
>
<span
role="menuitem"
tabIndex="0"
data-testid={`${metadataField}:category-expand`}
onKeyPress={(e) => {
if (e.key === "Enter") {
this.handleCategoryClick();
}
}}
style={{
cursor: "pointer",
display: "inline-block",
}}
onClick={() => {
const editingCategory =
annotations.isEditingCategoryName &&
annotations.categoryBeingEdited === metadataField;
if (!editingCategory) {
onExpansionChange(metadataField);
}
}}
onClick={this.handleCategoryClick}
>
{isUserAnno ? (
<Icon style={{ marginRight: 5 }} icon="tag" iconSize={16} />
+1 -1
View File
@@ -11,7 +11,7 @@ import LabelInput from "./labelInput";
import { labelPrompt } from "./labelUtil";
@connect((state) => ({
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false,
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
schema: state.world?.schema,
config: state.config,
ontology: state.ontology,
@@ -23,6 +23,9 @@ export default class LabelInput extends React.PureComponent {
* popoverProps -- will be passed to <Suggest>
*/
/* maxinum number of suggestions */
static QueryResultLimit = 100;
constructor(props) {
super(props);
@@ -103,9 +106,6 @@ export default class LabelInput extends React.PureComponent {
);
};
/* maxinum number of suggestions */
static QueryResultLimit = 100;
filterLabels(query) {
const { labelSuggestions } = this.props;
if (!labelSuggestions) return [];
@@ -62,6 +62,8 @@ class CategoryValue extends React.Component {
prevProps.metadataField !== metadataField ||
prevProps.categoryIndex !== categoryIndex
) {
// adequately checked to prevent looping
// eslint-disable-next-line react/no-did-update-set-state
this.setState({
editedLabelText: this.currentLabel(),
});
@@ -327,6 +329,8 @@ class CategoryValue extends React.Component {
annotations.isEditingLabelName &&
annotations.labelEditable.label === categoryIndex;
const valueToggleLabel = `value-toggle-checkbox-${displayString}`;
return (
<div
key={i}
@@ -360,8 +364,13 @@ class CategoryValue extends React.Component {
}}
>
<div style={{ display: "flex", alignItems: "baseline" }}>
<label className="bp3-control bp3-checkbox" style={{ margin: 0 }}>
<label
htmlFor={valueToggleLabel}
className="bp3-control bp3-checkbox"
style={{ margin: 0 }}
>
<input
id={valueToggleLabel}
onChange={selected ? this.toggleOff : this.toggleOn}
data-testclass="categorical-value-select"
data-testid={`categorical-value-select-${metadataField}-${displayString}`}
@@ -7,11 +7,6 @@ const ToastTopCenter = Toaster.create({
position: Position.TOP,
});
const ToastBottomCenter = Toaster.create({
className: "recipe-toaster",
position: Position.BOTTOM,
});
/*
A "user" error - eg, bad input
*/
@@ -262,7 +262,7 @@ class AddGenes extends React.Component {
}}
itemListPredicate={filterGenes}
onActiveItemChange={(item) => this.setState({ activeItem: item })}
itemRenderer={renderGene.bind(this)}
itemRenderer={renderGene}
items={varIndex || ["No genes"]}
popoverProps={{ minimal: true }}
/>
+30 -23
View File
@@ -10,7 +10,6 @@ import setupSVGandBrushElements from "./setupSVGandBrush";
import _camera from "../../util/camera";
import _drawPoints from "./drawPointsRegl";
import { isTypedArray } from "../../util/typeHelpers";
import styles from "./graph.css";
import GraphOverlayLayer from "./overlays/graphOverlayLayer";
import CentroidLabels from "./overlays/centroidLabels";
@@ -190,7 +189,7 @@ class Graph extends React.Component {
tool: null,
container: null,
cameraRender: 0,
viewport
viewport,
};
}
@@ -209,7 +208,10 @@ class Graph extends React.Component {
// create all default rendering transformations
const modelTF = createModelTF();
const projectionTF = createProjectionTF(this.reglCanvas.width, this.reglCanvas.height);
const projectionTF = createProjectionTF(
this.reglCanvas.width,
this.reglCanvas.height
);
// initial draw to canvas
this.renderPoints(
@@ -250,7 +252,8 @@ class Graph extends React.Component {
} = this.props;
const { regl, toolSVG, camera, modelTF, viewport } = this.state;
let { projectionTF } = this.state;
const hasResized = prevState.viewport.height !== this.reglCanvas.height ||
const hasResized =
prevState.viewport.height !== this.reglCanvas.height ||
prevState.viewport.width !== this.reglCanvas.width;
let stateChanges = {};
let needsRepaint = hasResized;
@@ -261,7 +264,10 @@ class Graph extends React.Component {
const { drawPoints, pointBuffer, colorBuffer, flagBuffer } = this.state;
if (hasResized) {
projectionTF = createProjectionTF(this.reglCanvas.width, this.reglCanvas.height);
projectionTF = createProjectionTF(
this.reglCanvas.width,
this.reglCanvas.height
);
stateChanges = {
...stateChanges,
projectionTF,
@@ -322,7 +328,10 @@ class Graph extends React.Component {
...stateChanges,
...this.createToolSVG(),
};
} else if ((viewport.height && viewport.width && !toolSVG) || selectionTool !== prevProps.selectionTool ) {
} else if (
(viewport.height && viewport.width && !toolSVG) ||
selectionTool !== prevProps.selectionTool
) {
// first time or change of selection tool
stateChanges = { ...stateChanges, ...this.createToolSVG() };
} else if (prevProps.graphInteractionMode !== graphInteractionMode) {
@@ -349,6 +358,7 @@ class Graph extends React.Component {
);
}
if (Object.keys(stateChanges).length > 0) {
// Preventing update loop via stateChanges and diff checks
// eslint-disable-next-line react/no-did-update-set-state
this.setState(stateChanges);
}
@@ -371,12 +381,11 @@ class Graph extends React.Component {
const { viewportRef } = this.props;
return {
height: viewportRef.clientHeight,
width: viewportRef.clientWidth
width: viewportRef.clientWidth,
};
};
handleCanvasEvent = e => {
handleCanvasEvent = (e) => {
const { camera, projectionTF } = this.state;
if (e.type !== "wheel") e.preventDefault();
if (camera.handleEvent(e, projectionTF)) {
@@ -547,12 +556,8 @@ class Graph extends React.Component {
vec2.transformMat3(xy, xy, projectionTF);
return [
Math.round(
(xy[0] + 1) * viewport.width / 2
),
Math.round(
-((xy[1] + 1) / 2 - 1) * viewport.height
)
Math.round(((xy[0] + 1) * viewport.width) / 2),
Math.round(-((xy[1] + 1) / 2 - 1) * viewport.height),
];
}
@@ -698,7 +703,7 @@ class Graph extends React.Component {
count: this.count,
projView,
nPoints: universe.nObs,
minViewportDimension: Math.min(width, height)
minViewportDimension: Math.min(width, height),
});
regl._gl.flush();
}
@@ -744,9 +749,11 @@ class Graph extends React.Component {
cameraTF={cameraTF}
modelTF={modelTF}
projectionTF={projectionTF}
handleCanvasEvent={graphInteractionMode === "zoom" ? this.handleCanvasEvent : undefined}
handleCanvasEvent={
graphInteractionMode === "zoom" ? this.handleCanvasEvent : undefined
}
>
<CentroidLabels/>
<CentroidLabels />
</GraphOverlayLayer>
<svg
id="lasso-layer"
@@ -756,13 +763,11 @@ class Graph extends React.Component {
position: "absolute",
top: 0,
left: 0,
zIndex: 1
zIndex: 1,
}}
width={viewport.width}
height={viewport.height}
pointerEvents={
graphInteractionMode === "select" ? "auto" : "none"
}
pointerEvents={graphInteractionMode === "select" ? "auto" : "none"}
/>
<canvas
width={viewport.width}
@@ -777,7 +782,9 @@ class Graph extends React.Component {
}}
className="graph-canvas"
data-testid="layout-graph"
ref={canvas => { this.reglCanvas = canvas; }}
ref={(canvas) => {
this.reglCanvas = canvas;
}}
onMouseDown={this.handleCanvasEvent}
onMouseUp={this.handleCanvasEvent}
onMouseMove={this.handleCanvasEvent}
@@ -1,5 +1,3 @@
/* eslint-disable max-classes-per-file */
/* eslint-disable jsx-a11y/mouse-events-have-key-events */
import React, { PureComponent } from "react";
import { connect } from "react-redux";
@@ -26,7 +24,7 @@ class CentroidLabels extends PureComponent {
// Notify overlay layer of display change
overlayToggled("centroidLabels", displayChangeOn);
}
};
}
render() {
const {
@@ -59,6 +57,7 @@ class CentroidLabels extends PureComponent {
labelSVGS.push(
<g
// label is unique so disabling eslint rule
// eslint-disable-next-line react/no-array-index-key
key={label}
className="centroid-label"
@@ -66,6 +65,8 @@ class CentroidLabels extends PureComponent {
data-testclass="centroid-label"
data-testid={`${label}-centroid-label`}
>
{/* The mouse actions for centroid labels do not have a screen reader alternative */}
{/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */}
<text
transform={inverseTransform}
textAnchor="middle"
@@ -2,8 +2,7 @@ import React, { PureComponent, cloneElement } from "react";
import styles from "../graph.css";
export default
class GraphOverlayLayer extends PureComponent {
export default class GraphOverlayLayer extends PureComponent {
/*
This component takes its children (assumed in the data coordinate space ([0, 1] range, origin in bottom left corner))
and transforms itself multiple times resulting in screen space ([0, screenWidth/Height] range, origin in top left corner)
@@ -49,7 +48,6 @@ class GraphOverlayLayer extends PureComponent {
handleCanvasEvent,
width,
height,
style
} = this.props;
const { display } = this.state;
@@ -63,7 +61,7 @@ class GraphOverlayLayer extends PureComponent {
cameraTF
)} ${this.reverseMatrixScaleTransformString(
projectionTF
)} scale(1 2) scale(1 ${1 / (-height)}) scale(2 1) scale(${1 / width} 1)`;
)} scale(1 2) scale(1 ${1 / -height}) scale(2 1) scale(${1 / width} 1)`;
// Copy the children passed with the overlay and add the inverse transform and onDisplayChange props
const newChildren = React.Children.map(children, (child) =>
@@ -4,7 +4,7 @@ import { connect } from "react-redux";
import * as globals from "../../globals";
import Logo from "../framework/logo";
@connect(state => ({
@connect((state) => ({
datasetTitle: state.config?.displayNames?.dataset ?? "",
aboutURL: state.config?.links?.["about-dataset"],
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
@@ -75,7 +75,7 @@ class LeftSideBar extends React.Component {
title={datasetTitle}
>
{aboutURL ? (
<a href={aboutURL} target="_blank">
<a href={aboutURL} target="_blank" rel="noopener noreferrer">
{displayTitle}
</a>
) : (
@@ -45,7 +45,9 @@ class CellSetButton extends React.PureComponent {
<AnchorButton
type="button"
disabled={differential.diffExp}
onClick={this.set.bind(this)}
onClick={() => {
this.set();
}}
data-testid={`cellset-button-${eitherCellSetOneOrTwo}`}
>
{eitherCellSetOneOrTwo}
@@ -1,14 +1,7 @@
// jshint esversion: 6
import React from "react";
import { connect } from "react-redux";
import {
Popover,
Button,
ButtonGroup,
AnchorButton,
Tooltip,
Position,
} from "@blueprintjs/core";
import { Button, ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
import * as globals from "../../globals";
import styles from "./menubar.css";
import actions from "../../actions";
@@ -21,16 +14,9 @@ import CellSetButton from "./cellSetButtons";
celllist1: state.differential?.celllist1,
celllist2: state.differential?.celllist2,
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max,
diffexpCellcountMax: state.config?.limits?.["diffexp_cellcount_max"],
}))
class DiffexpButtons extends React.Component {
constructor(props) {
super(props);
this.state = {
userDismissedPopover: false,
};
}
computeDiffExp = () => {
const { dispatch, differential } = this.props;
if (differential.celllist1 && differential.celllist2) {
@@ -54,16 +40,9 @@ class DiffexpButtons extends React.Component {
});
};
handlePopoverDismiss = () => {
this.setState({
userDismissedPopover: true,
});
};
render() {
/* diffexp-related buttons may be disabled */
const { differential, diffexpMayBeSlow, diffexpCellcountMax } = this.props;
const { userDismissedPopover } = this.state;
const haveBothCellSets =
!!differential.celllist1 && !!differential.celllist2;
@@ -86,7 +65,7 @@ class DiffexpButtons extends React.Component {
diffexpCellcountMax;
return (
<ButtonGroup className={styles.menubarButton} >
<ButtonGroup className={styles.menubarButton}>
<CellSetButton
{...this.props} // eslint-disable-line react/jsx-props-no-spreading
eitherCellSetOneOrTwo={1}
+1 -3
View File
@@ -69,9 +69,7 @@ class Embedding extends React.PureComponent {
const { layoutChoice } = this.props;
return (
<ButtonGroup
className={styles.menubarButton}
>
<ButtonGroup className={styles.menubarButton}>
<Popover
target={
<Tooltip
+79 -76
View File
@@ -1,7 +1,7 @@
// jshint esversion: 6
import React from "react";
import { connect } from "react-redux";
import { Button, ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
import { ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
import * as globals from "../../globals";
import styles from "./menubar.css";
@@ -28,7 +28,7 @@ import DiffexpButtons from "./diffexpButtons";
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
celllist1: state.differential.celllist1,
celllist2: state.differential.celllist2,
libraryVersions: state.config?.library_versions, // eslint-disable-line camelcase
libraryVersions: state.config?.["library_versions"],
undoDisabled: state["@@undoable/past"].length === 0,
redoDisabled: state["@@undoable/future"].length === 0,
aboutLink: state.config?.links?.["about-dataset"],
@@ -207,9 +207,10 @@ class MenuBar extends React.Component {
const { pendingClipPercentiles } = this.state;
// constants used to create selection tool button
const [selectionTooltip, selectionButtonIcon] = selectionTool === "brush"
? ["Brush selection", "Lasso selection"]
: ["select", "polygon-filter"];
const [selectionTooltip, selectionButtonIcon] =
selectionTool === "brush"
? ["Brush selection", "Lasso selection"]
: ["select", "polygon-filter"];
return (
<div
@@ -245,80 +246,82 @@ class MenuBar extends React.Component {
handleClipCommit={this.handleClipCommit}
isClipDisabled={this.isClipDisabled}
handleClipOnKeyPress={this.handleClipOnKeyPress}
handleClipPercentileMaxValueChange={this.handleClipPercentileMaxValueChange}
handleClipPercentileMinValueChange={this.handleClipPercentileMinValueChange}
handleClipPercentileMaxValueChange={
this.handleClipPercentileMaxValueChange
}
handleClipPercentileMinValueChange={
this.handleClipPercentileMinValueChange
}
/>
<Embedding />
<Tooltip
content="When a category is colored by, show labels on the graph"
position="bottom"
disabled={graphInteractionMode === "zoom"}
>
<AnchorButton
className={styles.menubarButton}
type="button"
data-testid="centroid-label-toggle"
icon="property"
onClick={this.handleCentroidChange}
active={showCentroidLabels}
intent={showCentroidLabels ? "primary" : "none"}
/>
</Tooltip>
<ButtonGroup
className={styles.menubarButton}
>
<Tooltip
content={selectionTooltip}
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
type="button"
data-testid="mode-lasso"
icon={selectionButtonIcon}
active={graphInteractionMode === "select"}
onClick={() => {
dispatch({
type: "change graph interaction mode",
data: "select"
});
<Embedding />
<Tooltip
content="When a category is colored by, show labels on the graph"
position="bottom"
disabled={graphInteractionMode === "zoom"}
>
<AnchorButton
className={styles.menubarButton}
type="button"
data-testid="centroid-label-toggle"
icon="property"
onClick={this.handleCentroidChange}
active={showCentroidLabels}
intent={showCentroidLabels ? "primary" : "none"}
/>
</Tooltip>
<ButtonGroup className={styles.menubarButton}>
<Tooltip
content={selectionTooltip}
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
type="button"
data-testid="mode-lasso"
icon={selectionButtonIcon}
active={graphInteractionMode === "select"}
onClick={() => {
dispatch({
type: "change graph interaction mode",
data: "select",
});
}}
/>
</Tooltip>
<Tooltip
content="Drag to pan, scroll to zoom"
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
type="button"
data-testid="mode-pan-zoom"
icon="zoom-in"
active={graphInteractionMode === "zoom"}
onClick={() => {
dispatch({
type: "change graph interaction mode",
data: "zoom",
});
}}
/>
</Tooltip>
</ButtonGroup>
<Subset
subsetPossible={this.subsetPossible()}
subsetResetPossible={this.subsetResetPossible()}
handleSubset={() => {
dispatch(actions.setWorldToSelection());
dispatch({ type: "increment graph render counter" });
}}
handleSubsetReset={() => {
dispatch(actions.resetWorldToUniverse());
dispatch({ type: "increment graph render counter" });
}}
/>
</Tooltip>
<Tooltip
content="Drag to pan, scroll to zoom"
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
type="button"
data-testid="mode-pan-zoom"
icon="zoom-in"
active={graphInteractionMode === "zoom"}
onClick={() => {
dispatch({
type: "change graph interaction mode",
data: "zoom"
});
}}
/>
</Tooltip>
</ButtonGroup>
<Subset
subsetPossible={this.subsetPossible()}
subsetResetPossible={this.subsetResetPossible()}
handleSubset={() => {
dispatch(actions.setWorldToSelection());
dispatch({ type: "increment graph render counter" });
}}
handleSubsetReset={() => {
dispatch(actions.resetWorldToUniverse());
dispatch({ type: "increment graph render counter" });
}}
/>
{disableDiffexp ? null : <DiffexpButtons/>}
</div>
);
{disableDiffexp ? null : <DiffexpButtons />}
</div>
);
}
}
@@ -141,7 +141,7 @@ class Scatterplot extends React.PureComponent {
viewport: {
height: null,
width: null,
}
},
};
}
@@ -190,7 +190,7 @@ class Scatterplot extends React.PureComponent {
svg,
drawPoints,
projectionTF,
viewport
viewport,
});
}
@@ -286,20 +286,11 @@ class Scatterplot extends React.PureComponent {
return {
viewport: {
height: window.height,
width: window.width
}
width: window.width,
},
};
};
handleResize = () => {
const { state } = this.state;
const viewport = this.getViewportDimensions();
this.setState({
...state,
viewport,
});
};
static setupScales(expressionX, expressionY) {
const xScale = d3
.scaleLinear()
@@ -316,6 +307,15 @@ class Scatterplot extends React.PureComponent {
};
}
handleResize = () => {
const { state } = this.state;
const viewport = this.getViewportDimensions();
this.setState({
...state,
viewport,
});
};
updateViewportDimensions = () => {
this.setState(this.getViewportDimensions());
};
@@ -390,7 +390,7 @@ class Scatterplot extends React.PureComponent {
minViewportDimension: Math.min(
viewport.width - globals.leftSidebarWidth || width,
viewport.height || height
)
),
});
regl._gl.flush();
}
+14 -15
View File
@@ -8,8 +8,6 @@ import {
Colors,
Icon,
} from "@blueprintjs/core";
import * as globals from "../../globals";
import { termsOfServiceToast } from "../framework/toasters";
const CookieDecision = "cxg.cookieDecision";
@@ -26,12 +24,14 @@ function storageGet(key, defaultValue = null) {
function storageSet(key, value) {
try {
window.localStorage.setItem(key, value);
} catch {}
} catch {
// continue
}
}
@connect((state) => ({
tosURL: state.config?.parameters?.about_legal_tos,
privacyURL: state.config?.parameters?.about_legal_privacy,
tosURL: state.config?.parameters?.["about_legal_tos"],
privacyURL: state.config?.parameters?.["about_legal_privacy"],
}))
class TermsPrompt extends React.PureComponent {
constructor(props) {
@@ -59,7 +59,9 @@ class TermsPrompt extends React.PureComponent {
if (window.cookieDecisionCallback instanceof Function) {
try {
window.cookieDecisionCallback();
} catch (e) {}
} catch (e) {
// continue
}
}
};
@@ -82,6 +84,7 @@ class TermsPrompt extends React.PureComponent {
}}
href={tosURL}
target="_blank"
rel="noopener noreferrer"
>
terms of service
</a>
@@ -103,6 +106,7 @@ class TermsPrompt extends React.PureComponent {
}}
href={privacyURL}
target="_blank"
rel="noopener noreferrer"
>
privacy policy
</a>
@@ -118,12 +122,10 @@ class TermsPrompt extends React.PureComponent {
<Drawer
onclose={this.drawerClose}
isOpen={isOpen}
size={"120px"}
size="120px"
position={Position.BOTTOM}
canOutsideClickClose={false}
hasBackdrop={
true /* if the user can't use the app or click outside to dismiss, that should be visually represented with a backdrop */
}
hasBackdrop /* if the user can't use the app or click outside to dismiss, that should be visually represented with a backdrop */
enforceFocus={false}
autoFocus={false}
portal={false}
@@ -149,12 +151,9 @@ class TermsPrompt extends React.PureComponent {
onClick={this.handleOK}
data-testid="tos-cookies-accept"
>
I'm OK with cookies!
I&apos;m OK with cookies!
</Button>{" "}
<Button
onClick={this.handleNo}
data-testid="tos-cookies-reject"
>
<Button onClick={this.handleNo} data-testid="tos-cookies-reject">
No thanks
</Button>
</div>
-1
View File
@@ -1,5 +1,4 @@
// jshint esversion: 6
/* eslint-disable no-console */
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
+1 -1
View File
@@ -150,7 +150,7 @@ const ColorsReducer = (
case "annotation: delete label": {
const { world } = nextSharedState;
const { colorMode, colorAccessor } = state;
const { metadataField, colors } = action;
const { metadataField } = action;
if (
colorMode !== "color by categorical metadata" ||
colorAccessor !== metadataField
+1 -1
View File
@@ -49,7 +49,7 @@ const LayoutChoice = (
}
case "reembed: add reembedding": {
const name = action.schema.name;
const { name } = action.schema;
const available = Array.from(new Set(state.available).add(name));
return {
...state,
+5 -4
View File
@@ -9,11 +9,12 @@ const Ontology = (
) => {
switch (action.type) {
case "configuration load complete": {
/* eslint-disable camelcase */
const enabled =
action.config?.parameters?.annotations_cell_ontology_enabled ?? false;
const terms = action.config?.parameters?.annotations_cell_ontology_terms;
/* eslint-enable camelcase */
action.config?.parameters?.["annotations_cell_ontology_enabled"] ??
false;
const terms =
action.config?.parameters?.["annotations_cell_ontology_terms"];
const termSet = new Set(terms);
return {
...state,
+3 -3
View File
@@ -41,8 +41,8 @@ const WorldReducer = (
const { dim } = action;
// we don't clip anything except for varData and obsAnnotations
let unclipped = state.unclipped;
if (dim == "varData" || dim == "obsAnnotations") {
let { unclipped } = state;
if (dim === "varData" || dim === "obsAnnotations") {
unclipped = {
...unclipped,
[dim]: universe[dim].clone(),
@@ -298,7 +298,7 @@ const WorldReducer = (
const { obsLayout: origObsLayout, schema: origSchema } = state;
const { embedding, schema: embeddingSchema } = action;
const { dims, name } = embeddingSchema;
const { dims } = embeddingSchema;
let obsLayout = origObsLayout;
let schema = origSchema;
+4 -6
View File
@@ -1,3 +1,4 @@
/* eslint-disable max-classes-per-file */
/**
Label indexing - map a label to & from an integer offset. See Dataframe
for how this is used.
@@ -23,7 +24,6 @@ function extent(tarr) {
return [min, max];
}
/* eslint-disable class-methods-use-this */
class IdentityInt32Index {
/*
identity/noop index, with small assumptions that labels are int32
@@ -41,11 +41,13 @@ class IdentityInt32Index {
return k;
}
// eslint-disable-next-line class-methods-use-this
getOffset(i) {
// label to offset
return i;
}
// eslint-disable-next-line class-methods-use-this
getLabel(i) {
// offset to label
return i;
@@ -93,9 +95,6 @@ class IdentityInt32Index {
return this.__promote(labelArray);
}
}
/* eslint-enable class-methods-use-this */
/* eslint-disable class-methods-use-this */
class DenseInt32Index {
/*
DenseInt32Index indexes integer labels, and uses Int32Array typed arrays
@@ -177,9 +176,7 @@ class DenseInt32Index {
return this.__promote(labelArray);
}
}
/* eslint-enable class-methods-use-this */
/* eslint-disable class-methods-use-this */
class KeyIndex {
/*
KeyIndex indexes arbitrary JS primitive types, and uses a Map()
@@ -223,6 +220,7 @@ class KeyIndex {
return this.rindex.length;
}
// eslint-disable-next-line class-methods-use-this
subsetLabels(labelArray) {
return new KeyIndex(labelArray);
}
+1 -1
View File
@@ -13,7 +13,7 @@ return Promise.all([
plimit.add(() => fetch('/baz'))
])
*/
export class PromiseLimit {
export default class PromiseLimit {
constructor(maxConcurrency) {
this.queue = new Set();
this.maxConcurrency = maxConcurrency;
+1 -1
View File
@@ -5,6 +5,6 @@
export default (n) => {
return n
.toExponential()
.replace(/e[\+\-0-9]*$/, "")
.replace(/e[+\-0-9]*$/, "")
.replace(/^0\.?0*|\./, "").length;
};
@@ -1,3 +1,4 @@
// eslint-disable-next-line max-classes-per-file
import PositiveIntervals from "./positiveIntervals";
import BitArray from "./bitArray";
import {
@@ -409,7 +410,7 @@ class ImmutableScalarDimension extends _ImmutableBaseDimension {
this.index = makeSortIndex(array);
}
/* eslint-disable class-methods-use-this */
// eslint-disable-next-line class-methods-use-this
_createValueArray(data, mapf, array) {
// create dimension value array
const len = data.length;
@@ -419,7 +420,6 @@ class ImmutableScalarDimension extends _ImmutableBaseDimension {
}
return larray;
}
/* eslint-enable class-methods-use-this */
select(spec) {
const { mode } = spec;
@@ -466,7 +466,7 @@ class ImmutableScalarDimension extends _ImmutableBaseDimension {
const ranges = [];
const r = [
lowerBoundIndirect(value, index, lo, 0, value.length),
!!inclusive
inclusive
? upperBoundIndirect(value, index, hi, 0, value.length)
: lowerBoundIndirect(value, index, hi, 0, value.length),
];
@@ -514,11 +514,10 @@ class ImmutableEnumDimension extends ImmutableScalarDimension {
});
}
/* eslint-disable class-methods-use-this */
// eslint-disable-next-line class-methods-use-this
selectRange() {
throw new Error("range selection unsupported on Enumerated dimension");
}
/* eslint-enable class-methods-use-this */
}
class ImmutableSpatialDimension extends _ImmutableBaseDimension {