Compare commits

...
Author SHA1 Message Date
kaloster 012d3b8b9e flakey test 2024-09-12 21:02:42 -04:00
Timmy Huang 151c28d119 chore: Add ESLint no-floating-promise 2024-09-12 13:36:26 -07:00
27 changed files with 841 additions and 729 deletions
+8 -3
View File
@@ -7,6 +7,10 @@ on:
branches:
- main
# For debug - uncomment below to run on all PRs
pull_request:
branches: "*"
env:
JEST_ENV: prod
@@ -28,13 +32,14 @@ jobs:
strategy:
fail-fast: false
matrix:
# note: The `macos-latest` is latest Catalina version, and not Big Sur. So we explicitly ask for Big Sur (`macos-11`)
os: [ubuntu-latest, macos-latest, macos-13]
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11"]
cellxgene_build: [main, latest]
# add anndata pinned version test for subset of matrix configurations,
# in order to reduce matrix cross-product explosion
include:
- python-version: 3.12
- python-version: 3.11
cellxgene_build: latest
# TODO: dynamically use the literal version in requirements.txt,
# to avoid having to update this in manually in the future
@@ -95,7 +100,7 @@ jobs:
# keep same pip pkg versions as in the cxg release
sed -i'' -e 's/-r requirements.txt//' server/requirements-dev.txt
pip install -r server/requirements-dev.txt
pip install --force-reinstall numpy==2.0.1 numba>=0.60.0 pandas flatbuffers==2.0.7
pip install --force-reinstall numpy==2.0.1 numba>=0.60.0 pandas
- name: Install anndata version per matrix variable
run: pip install anndata${{ matrix.anndata_version }}
- name: Install node
+3 -2
View File
@@ -1,4 +1,4 @@
<img src="./docs/cellxgene-logo.png" width="300">
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/cellxgene-logo.png)
_an interactive explorer for single-cell transcriptomics data_
@@ -11,7 +11,8 @@ CZ CELLxGENE Annotate (pronounced "cell-by-gene") is an interactive data explore
Whether you need to visualize one thousand cells or one million, CELLxGENE Annotate helps you gain insight into your single-cell data.
<img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif" width="350" height="200" hspace="30"><img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif" width="350" height="200" hspace="30">
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif)
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif)
# Getting started
+1 -1
View File
@@ -1,4 +1,4 @@
import * as ENV_DEFAULT from "../../../environment.default.json";
import * as ENV_DEFAULT from "Code/cellxgene/environment.default.json";
export const jestEnv = process.env.JEST_ENV || ENV_DEFAULT.JEST_ENV;
export const appUrlBase =
+1 -1
View File
@@ -5,8 +5,8 @@
*/
import { setDefaultOptions } from "expect-puppeteer";
import * as ENV_DEFAULT from "Code/cellxgene/environment.default.json";
import { isDebug, isDev } from "./config";
import * as ENV_DEFAULT from "../../../environment.default.json";
// (thuang): This is the max time a test can take to run.
// Since when debugging, we run slowMo and !headless, this means
+6 -6
View File
@@ -76,7 +76,7 @@ describe("PromiseLimit", () => {
const plimit = new PromiseLimit(1);
let finishOrder = 0;
const callback = () => async () => {
const callback = async () => {
await delay(100);
const result = finishOrder;
finishOrder += 1;
@@ -84,11 +84,11 @@ describe("PromiseLimit", () => {
};
const result = await Promise.all([
plimit.add(callback()),
plimit.priorityAdd(4, callback()),
plimit.priorityAdd(0, callback()),
plimit.priorityAdd(1, callback()),
plimit.priorityAdd(-1, callback()),
plimit.add(callback),
plimit.priorityAdd(4, callback),
plimit.priorityAdd(0, callback),
plimit.priorityAdd(1, callback),
plimit.priorityAdd(-1, callback),
]);
expect(result).toEqual([0, 4, 2, 3, 1]);
+2 -1
View File
@@ -82,13 +82,14 @@ module.exports = {
},
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
// "extends": ["plugin:jest/recommended"]
plugins: ["jest"],
plugins: ["jest", "no-floating-promise"],
rules: {
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error",
"no-floating-promise/no-floating-promise": 2,
},
},
],
+774 -645
View File
File diff suppressed because it is too large Load Diff
+7 -6
View File
@@ -10,8 +10,8 @@
"dev": "npm run build -- configuration/webpack/webpack.config.dev.js",
"e2e": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.js",
"e2e-annotations": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2eAnnotations.test.js",
"fmt": "eslint --fix src __tests__",
"lint": "eslint --fix src __tests__",
"fmt": "eslint --fix __tests__",
"lint": "eslint --fix __tests__",
"prod": "npm run build -- configuration/webpack/webpack.config.prod.js",
"test": "jest --testPathIgnorePatterns e2e",
"prepare": "cd .. && husky install client/.husky"
@@ -92,7 +92,7 @@
"@babel/preset-react": "^7.13.13",
"@babel/register": "^7.13.16",
"@babel/runtime": "^7.13.16",
"@blueprintjs/eslint-plugin": "^0.3.0",
"@blueprintjs/eslint-plugin": "^6.1.4",
"@sentry/webpack-plugin": "^1.15.0",
"babel-jest": "^26.1.0",
"babel-loader": "^8.1.0",
@@ -104,15 +104,16 @@
"codecov": "^3.7.1",
"css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "^7.24.0",
"eslint-config-airbnb": "^18.2.0",
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.2.0",
"eslint-plugin-compat": "^4.2.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^24.3.5",
"eslint-plugin-jest": "^28.8.3",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-no-floating-promise": "^2.0.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.0.8",
"expect-puppeteer": "^5.0.0",
@@ -1,8 +1,8 @@
import React from "react";
import * as globals from "../../globals";
const ErrorLoading = ({ displayName, zebra }) => (
<div
function ErrorLoading({ displayName, zebra }) {
return <div
style={{
backgroundColor: zebra ? globals.lightestGrey : "white",
fontStyle: "italic",
@@ -10,6 +10,6 @@ const ErrorLoading = ({ displayName, zebra }) => (
>
<span>{`Failure loading ${displayName}`}</span>
</div>
);
}
export default ErrorLoading;
@@ -5,7 +5,7 @@ import * as d3 from "d3";
import maybeScientific from "../../util/maybeScientific";
import clamp from "../../util/clamp";
const Histogram = ({
function Histogram({
field,
fieldForId,
display,
@@ -18,7 +18,7 @@ const Histogram = ({
isColorBy,
selectionRange,
mini,
}) => {
}) {
const svgRef = useRef(null);
const [brush, setBrush] = useState(null);
@@ -186,6 +186,6 @@ const Histogram = ({
ref={svgRef}
/>
);
};
}
export default Histogram;
@@ -3,12 +3,8 @@ import { Button } from "@blueprintjs/core";
import * as globals from "../../globals";
const StillLoading = ({ zebra, displayName }) =>
/*
Render a loading indicator for the field.
*/
(
<div
function StillLoading({ zebra, displayName }) {
return <div
data-testclass="gene-loading-spinner"
style={{
padding: globals.leftSidebarSectionPadding,
@@ -37,7 +33,6 @@ const StillLoading = ({ zebra, displayName }) =>
</div>
</div>
</div>
)
;
}
export default StillLoading;
@@ -71,8 +71,7 @@ class Category extends React.PureComponent {
const { metadataField, annotations, obsCrossfilter } = this.props;
return (
<>
<AnnoDialog
<AnnoDialog
isActive={
annotations.isAddingNewLabel &&
annotations.categoryAddingNewLabel === metadataField
@@ -105,7 +104,6 @@ class Category extends React.PureComponent {
/>
}
/>
</>
);
}
}
@@ -105,8 +105,7 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
const { metadataField, annotations } = this.props;
return (
<>
<AnnoDialog
<AnnoDialog
isActive={
annotations.isEditingCategoryName &&
annotations.categoryBeingEdited === metadataField
@@ -141,7 +140,6 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
/>
}
/>
</>
);
}
}
@@ -288,11 +288,8 @@ class Category extends React.PureComponent {
export default Category;
const StillLoading = ({ metadataField, checkboxID }) => (
/*
We are still loading this category, so render a "busy" signal.
*/
<div
function StillLoading({ metadataField, checkboxID }) {
return <div
style={{
maxWidth: globals.maxControlsWidth,
}}
@@ -335,8 +332,8 @@ const StillLoading = ({ metadataField, checkboxID }) => (
</div>
</div>
</div>
);
const ErrorLoading = ({ metadataField, error }) => {
}
function ErrorLoading({ metadataField, error }) {
console.error(error); // log error to console as it is unexpected.
return (
<div style={{ marginBottom: 10, marginTop: 4 }}>
@@ -352,7 +349,7 @@ const ErrorLoading = ({ metadataField, error }) => {
</span>
</div>
);
};
}
const CategoryHeader = React.memo(
({
@@ -162,7 +162,7 @@ class CategoryValue extends React.Component {
);
};
shouldComponentUpdate = (nextProps, nextState) => {
shouldComponentUpdate(nextProps, nextState) {
/*
Checks to see if at least one of the following changed:
* world state
+2 -2
View File
@@ -109,7 +109,7 @@ const loadAllEmbeddingCounts = async ({ annoMatrix, available }) => {
}));
};
const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
function EmbeddingChoices({ onChange, annoMatrix, layoutChoice }) {
const { available } = layoutChoice;
const { data, error, isPending } = useAsync({
promiseFn: loadAllEmbeddingCounts,
@@ -149,4 +149,4 @@ const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
);
}
return null;
};
}
+2 -2
View File
@@ -1,7 +1,7 @@
import React from "react";
import icon from "../../images/icon.png";
const Logo = (props) => {
function Logo(props) {
const { size } = props;
return (
<img
@@ -11,6 +11,6 @@ const Logo = (props) => {
alt="CELLxGENE Annotate Logo"
/>
);
};
}
export default Logo;
@@ -53,8 +53,7 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
const { genesToAdd } = this.state;
return (
<>
<AnnoDialog
<AnnoDialog
isActive={genesetsUI.isAddingGenesToGeneset === geneset}
inputProps={{ "data-testid": `${geneset}:create-label-dialog` }}
primaryButtonProps={{
@@ -81,7 +80,6 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
handleSubmit={this.handleAddGeneToGeneSet}
handleCancel={this.disableAddGeneMode}
/>
</>
);
}
}
@@ -125,8 +125,7 @@ class CreateGenesetDialogue extends React.PureComponent {
const { genesetsUI, genesets } = this.props;
return (
<>
<Dialog
<Dialog
icon="tag"
title="Create gene set"
isOpen={genesetsUI.createGenesetModeActive}
@@ -210,7 +209,6 @@ class CreateGenesetDialogue extends React.PureComponent {
</div>
</form>
</Dialog>
</>
);
}
}
@@ -109,8 +109,7 @@ class RenameGeneset extends React.PureComponent {
} = this.props;
return (
<>
<AnnoDialog
<AnnoDialog
isActive={genesetsUI.isEditingGenesetName === originalGenesetName}
inputProps={{
"data-testid": `${genesetsUI.isEditingGenesetName}:rename-geneset-dialog`,
@@ -161,7 +160,6 @@ class RenameGeneset extends React.PureComponent {
handleSubmit={this.renameGeneset}
handleCancel={this.disableEditGenesetNameMode}
/>
</>
);
}
}
+5 -10
View File
@@ -935,7 +935,7 @@ class Graph extends React.Component {
}
}
const ErrorLoading = ({ displayName, error, width, height }) => {
function ErrorLoading({ displayName, error, width, height }) {
console.log(error); // log to console as this is an unepected error
return (
<div
@@ -949,14 +949,10 @@ const ErrorLoading = ({ displayName, error, width, height }) => {
<span>{`Failure loading ${displayName}`}</span>
</div>
);
};
}
const StillLoading = ({ displayName, width, height }) =>
/*
Render a busy/loading indicator
*/
(
<div
function StillLoading({ displayName, width, height }) {
return <div
style={{
position: "fixed",
fontWeight: 500,
@@ -976,7 +972,6 @@ const StillLoading = ({ displayName, width, height }) =>
<span style={{ fontStyle: "italic" }}>Loading {displayName}</span>
</div>
</div>
)
;
}
export default Graph;
@@ -167,7 +167,7 @@ class CentroidLabels extends PureComponent {
}
}
const Label = ({
function Label({
label,
dilatedValue,
coords,
@@ -177,7 +177,7 @@ const Label = ({
displayLabel,
onMouseEnter,
onMouseOut,
}) => {
}) {
/*
Render a label at a given coordinate.
*/
@@ -215,4 +215,4 @@ const Label = ({
</text>
</g>
);
};
}
+1 -3
View File
@@ -159,8 +159,7 @@ export default class LabelInput extends React.PureComponent {
};
const { queryResults } = this.state;
return (
<>
<Suggest
<Suggest
fill
inputValueRenderer={(i) => i.target}
items={queryResults}
@@ -172,7 +171,6 @@ export default class LabelInput extends React.PureComponent {
inputProps={inputProps}
onKeyDown={this.handleKeyDown}
/>
</>
);
}
}
+2 -2
View File
@@ -35,11 +35,11 @@ export default class MiniHistogram extends React.PureComponent {
}
};
componentDidMount = () => {
componentDidMount() {
this.drawHistogram();
};
componentDidUpdate = (prevProps) => {
componentDidUpdate(prevProps) {
const { obsOrVarContinuousFieldDisplayName, bins } = this.props;
if (
prevProps.obsOrVarContinuousFieldDisplayName !==
@@ -42,12 +42,12 @@ export default class MiniStackedBar extends React.PureComponent {
}
};
componentDidUpdate = (prevProps) => {
componentDidUpdate(prevProps) {
const { occupancy } = this.props;
if (occupancy !== prevProps.occupancy) this.drawStacks();
};
componentDidMount = () => {
componentDidMount() {
this.drawStacks();
};
+1 -1
View File
@@ -32,7 +32,7 @@ const SECOND_HALF_INNER_STYLE = {
right: 0,
};
export default (props) => {
export default function(props) {
const { children, isGenesetDescription, tooltipAddendum = "" } = props;
// Truncate only support a single child with a text child
+1 -1
View File
@@ -1,6 +1,6 @@
import { Colors } from "@blueprintjs/core";
import ENV_DEFAULT from "Code/cellxgene/environment.default.json";
import { dispatchNetworkErrorMessageToUser } from "./util/actionHelpers";
import ENV_DEFAULT from "../../environment.default.json";
/* overflow category values are created using this string */
export const overflowCategoryLabel = ": all other labels";