From 6cccc41c0fbb97ab681d50bb7f2ae7f1c8cf47c8 Mon Sep 17 00:00:00 2001 From: Severiano Badajoz Date: Mon, 4 May 2020 10:26:42 -0700 Subject: [PATCH] run prettier(2.0.5) (#1438) --- client/__tests__/e2e/cellxgeneActions.js | 79 +++-- client/__tests__/e2e/config.js | 3 +- client/__tests__/e2e/data.js | 74 ++--- client/__tests__/e2e/e2e.test.js | 63 +++- client/__tests__/e2e/e2eAnnotations.test.js | 64 ++-- client/__tests__/e2e/e2eJestConfig.json | 8 +- client/__tests__/e2e/feature.test.js | 4 +- client/__tests__/e2e/puppeteerUtils.js | 16 +- client/__tests__/e2e/testBrowser.js | 33 +- client/__tests__/reducers/cascade.test.js | 6 +- client/__tests__/reducers/undoable.test.js | 6 +- client/__tests__/util/actionHelpers.test.js | 15 +- client/__tests__/util/centroid.test.js | 10 +- .../util/dataframe/dataframe.test.js | 38 +-- .../util/dataframe/histogram.test.js | 18 +- .../util/dataframe/summarize.test.js | 96 ++++-- client/__tests__/util/nameCreators.test.js | 16 +- client/__tests__/util/promiseLimit.test.js | 122 +++---- client/__tests__/util/quantile.test.js | 48 +-- client/__tests__/util/range.test.js | 72 ++-- .../util/stateManager/controlsHelpers.test.js | 13 +- .../__tests__/util/stateManager/fbs.test.js | 46 +-- .../util/stateManager/sampleResponses.js | 52 +-- .../util/stateManager/universe.test.js | 10 +- .../__tests__/util/stateManager/world.test.js | 24 +- .../util/typedCrossfilter/bitArray.test.js | 2 +- .../util/typedCrossfilter/crossfilter.test.js | 147 +++++--- .../typedCrossfilter/positiveInterval.test.js | 178 +++++++--- .../util/typedCrossfilter/sort.test.js | 8 +- .../util/typedCrossfilter/util.test.js | 2 +- client/configuration/babel/babel.dev.js | 6 +- client/configuration/babel/babel.prod.js | 6 +- client/configuration/eslint/eslint.js | 18 +- .../webpack/webpack.config.dev.js | 48 +-- client/index.html | 30 +- client/index_template.html | 109 +++--- client/server/development.js | 6 +- client/server/utils.js | 8 +- client/src/actions/index.js | 64 ++-- client/src/actions/reembed.js | 20 +- client/src/components/app.js | 16 +- .../src/components/autosave/filenameDialog.js | 22 +- client/src/components/autosave/index.js | 20 +- .../src/components/categorical/annoDialog.js | 10 +- .../src/components/categorical/annoSelect.js | 8 +- .../categorical/category/annoMenuCategory.js | 14 +- .../src/components/categorical/labelInput.js | 26 +- .../src/components/categorical/labelUtil.js | 84 ++--- .../continuous/setupParallelCoordinates.js | 2 +- client/src/components/continuous/util.js | 6 +- .../src/components/continuousLegend/index.js | 20 +- client/src/components/framework/container.js | 2 +- client/src/components/framework/logo.js | 2 +- client/src/components/geneExpression/index.js | 36 +- client/src/components/graph/drawPointsRegl.js | 8 +- client/src/components/graph/graph.js | 66 ++-- .../graph/overlays/centroidLabels.js | 18 +- .../graph/overlays/graphOverlayLayer.js | 33 +- client/src/components/graph/setupLasso.js | 13 +- .../src/components/graph/setupSVGandBrush.js | 2 +- .../leftSidebar/topLeftLogoAndTitle.js | 20 +- .../src/components/menubar/cellSetButtons.js | 4 +- client/src/components/menubar/clip.js | 14 +- .../src/components/menubar/diffexpButtons.js | 16 +- client/src/components/menubar/embedding.js | 20 +- client/src/components/menubar/index.js | 38 +-- client/src/components/menubar/infoMenu.js | 22 +- client/src/components/menubar/subset.js | 2 +- client/src/components/menubar/undoRedo.js | 10 +- client/src/components/rightSidebar/index.js | 8 +- .../components/scatterplot/drawPointsRegl.js | 8 +- .../src/components/scatterplot/scatterplot.js | 44 ++- .../scatterplot/setupScatterplot.js | 2 +- client/src/fonts/ATTRIBUTION.md | 6 +- client/src/index.css | 24 +- client/src/reducers/annotations.js | 20 +- client/src/reducers/autosave.js | 92 ++--- client/src/reducers/categoricalSelection.js | 22 +- client/src/reducers/centroidLabels.js | 10 +- client/src/reducers/colors.js | 31 +- client/src/reducers/config.js | 8 +- client/src/reducers/differential.js | 16 +- client/src/reducers/graphSelection.js | 18 +- client/src/reducers/layoutChoice.js | 14 +- client/src/reducers/ontology.js | 4 +- client/src/reducers/pointDilation.js | 4 +- client/src/reducers/reembed.js | 14 +- client/src/reducers/resetCache.js | 4 +- client/src/reducers/responsive.js | 4 +- client/src/reducers/undoable.js | 28 +- client/src/reducers/undoableConfig.js | 32 +- client/src/reducers/undoableFsm.js | 52 +-- client/src/reducers/universe.js | 22 +- client/src/reducers/world.js | 46 +-- client/src/util/camera.js | 6 +- client/src/util/catLabelSort.js | 2 +- client/src/util/centroid.js | 2 +- client/src/util/clip.js | 22 +- client/src/util/dataframe/dataframe.js | 24 +- client/src/util/dataframe/summarize.js | 4 +- client/src/util/fromEntries.js | 12 +- client/src/util/nameCreators.js | 8 +- client/src/util/parseRGB.js | 4 +- client/src/util/promiseLimit.js | 58 ++-- client/src/util/quantile.js | 18 +- client/src/util/range.js | 32 +- client/src/util/scaleLinear.js | 16 +- client/src/util/scaleRGB.js | 2 +- .../util/stateManager/annotationsHelpers.js | 230 ++++++------- client/src/util/stateManager/colorHelpers.js | 34 +- .../src/util/stateManager/controlsHelpers.js | 12 +- client/src/util/stateManager/matrix.js | 6 +- .../src/util/stateManager/matrix_generated.js | 314 +++++++++++------- client/src/util/stateManager/schemaHelpers.js | 26 +- client/src/util/stateManager/universe.js | 22 +- client/src/util/stateManager/world.js | 10 +- client/src/util/statemachine/index.js | 2 +- client/src/util/typeHelpers.js | 22 +- 118 files changed, 1979 insertions(+), 1584 deletions(-) diff --git a/client/__tests__/e2e/cellxgeneActions.js b/client/__tests__/e2e/cellxgeneActions.js index 18abcb92..fb8b12f4 100644 --- a/client/__tests__/e2e/cellxgeneActions.js +++ b/client/__tests__/e2e/cellxgeneActions.js @@ -1,7 +1,6 @@ import { strict as assert } from "assert"; export const cellxgeneActions = (page, utils) => ({ - async drag(testId, start, end, lasso = false) { const layout = await utils.waitByID(testId); const elBox = await layout.boxModel(); @@ -31,22 +30,29 @@ export const cellxgeneActions = (page, utils) => ({ }, async getAllHistograms(testclass, testIds) { - const histTestIds = testIds.map(tid => `histogram-${tid}`); + const histTestIds = testIds.map((tid) => `histogram-${tid}`); // these load asynchronously, so we need to wait for each histogram individually await utils.waitForAllByIds(histTestIds); const allHistograms = await utils.getAllByClass(testclass); - return allHistograms.map(hist => hist.replace(/^histogram-/, "")); + return allHistograms.map((hist) => hist.replace(/^histogram-/, "")); }, async getAllCategoriesAndCounts(category) { await utils.waitByClass("categorical-row"); return page.$$eval( `[data-testid="category-${category}"] [data-testclass='categorical-row']`, - rows => Object.fromEntries(rows.map(row => { - const cat = row.querySelector("[data-testclass='categorical-value']").innerText; - const count = row.querySelector("[data-testclass='categorical-value-count']").innerText; - return [cat, count]; - })) + (rows) => + Object.fromEntries( + rows.map((row) => { + const cat = row.querySelector( + "[data-testclass='categorical-value']" + ).innerText; + const count = row.querySelector( + "[data-testclass='categorical-value-count']" + ).innerText; + return [cat, count]; + }) + ) ); }, @@ -60,12 +66,14 @@ export const cellxgeneActions = (page, utils) => ({ await utils.waitByID(checkboxId); const checkedPseudoclass = await page.$eval( `[data-testid='${checkboxId}']`, - el => el.matches(":checked") + (el) => el.matches(":checked") ); if (!checkedPseudoclass) await utils.clickOn(checkboxId); try { const categoryRow = await utils.waitByID(`${category}:category-expand`); - const isExpanded = await categoryRow.$("[data-testclass='category-expand-is-expanded']"); + const isExpanded = await categoryRow.$( + "[data-testclass='category-expand-is-expanded']" + ); if (isExpanded) await utils.clickOn(`${category}:category-expand`); } catch {} }, @@ -75,14 +83,22 @@ export const cellxgeneActions = (page, utils) => ({ const size = await el.boxModel(); return { x: Math.floor(size.width * xAsPercent), - y: Math.floor(size.height * yAsPercent) - } + y: Math.floor(size.height * yAsPercent), + }; }, async calcDragCoordinates(testId, coordinateAsPercent) { return { - start: await this.calcCoordinate(testId, coordinateAsPercent.x1, coordinateAsPercent.y1), - end: await this.calcCoordinate(testId, coordinateAsPercent.x2, coordinateAsPercent.y2) + start: await this.calcCoordinate( + testId, + coordinateAsPercent.x1, + coordinateAsPercent.y1 + ), + end: await this.calcCoordinate( + testId, + coordinateAsPercent.x2, + coordinateAsPercent.y2 + ), }; }, @@ -97,7 +113,9 @@ export const cellxgeneActions = (page, utils) => ({ async expandCategory(category) { const expand = await utils.waitByID(`${category}:category-expand`); - const notExpanded = await expand.$("[data-testclass='category-expand-is-not-expanded']"); + const notExpanded = await expand.$( + "[data-testclass='category-expand-is-not-expanded']" + ); if (notExpanded) await utils.clickOn(`${category}:category-expand`); }, @@ -117,7 +135,10 @@ export const cellxgeneActions = (page, utils) => ({ async renameCategory(oldCatgoryName, newCategoryName) { await utils.clickOn(`${oldCatgoryName}:see-actions`); await utils.clickOn(`${oldCatgoryName}:edit-category-mode`); - await utils.clearInputAndTypeInto(`${oldCatgoryName}:edit-category-name-text`, newCategoryName); + await utils.clearInputAndTypeInto( + `${oldCatgoryName}:edit-category-name-text`, + newCategoryName + ); await utils.clickOn(`${oldCatgoryName}:submit-category-edit`); }, @@ -136,7 +157,7 @@ export const cellxgeneActions = (page, utils) => ({ async deleteLabel(categoryName, labelName) { await this.expandCategory(categoryName); await utils.clickOn(`${categoryName}:${labelName}:see-actions`); - await utils.clickOn( `${categoryName}:${labelName}:delete-label`); + await utils.clickOn(`${categoryName}:${labelName}:delete-label`); }, async renameLabel(categoryName, oldLabelName, newLabelName) { @@ -153,17 +174,23 @@ export const cellxgeneActions = (page, utils) => ({ async addGeneToSearch(geneName) { await utils.typeInto("gene-search", geneName); await page.keyboard.press("Enter"); - await page.waitForSelector( - `[data-testid='histogram-${geneName}']` - ); + await page.waitForSelector(`[data-testid='histogram-${geneName}']`); }, async subset(coordinatesAsPercent) { // In order to deselect the selection after the subset, make sure we have some clear part // of the scatterplot we can click on assert(coordinatesAsPercent.x2 < 0.99 || coordinatesAsPercent.y2 < 0.99); - const lassoSelection = await this.calcDragCoordinates( "layout-graph", coordinatesAsPercent); - await this.drag("layout-graph", lassoSelection.start, lassoSelection.end, true ); + const lassoSelection = await this.calcDragCoordinates( + "layout-graph", + coordinatesAsPercent + ); + await this.drag( + "layout-graph", + lassoSelection.start, + lassoSelection.end, + true + ); await utils.clickOn("subset-button"); const clearCoordinate = await this.calcCoordinate( "layout-graph", @@ -174,7 +201,9 @@ export const cellxgeneActions = (page, utils) => ({ }, async setSellSet(cellSet, cellSetNum) { - for (const selection of cellSet.filter(sel => sel.kind === "categorical")) { + for (const selection of cellSet.filter( + (sel) => sel.kind === "categorical" + )) { await this.selectCategory(selection.metadata, selection.values, true); } await this.cellSet(cellSetNum); @@ -190,7 +219,5 @@ export const cellxgeneActions = (page, utils) => ({ await utils.clickOn("section-bulk-add"); await utils.typeInto("input-bulk-add", geneNames.join(",")); await page.keyboard.press("Enter"); - } + }, }); - - diff --git a/client/__tests__/e2e/config.js b/client/__tests__/e2e/config.js index c287762d..d4748edd 100644 --- a/client/__tests__/e2e/config.js +++ b/client/__tests__/e2e/config.js @@ -1,6 +1,7 @@ export const jest_env = process.env.JEST_ENV; export const appPort = process.env.CXG_SERVER_PORT; -export const appUrlBase = process.env.CXG_URL_BASE || `http://localhost:${appPort}`; +export const appUrlBase = + process.env.CXG_URL_BASE || `http://localhost:${appPort}`; export const DEV = jest_env === "dev"; export const DEBUG = jest_env === "debug"; export const DATASET = "pbmc3k"; diff --git a/client/__tests__/e2e/data.js b/client/__tests__/e2e/data.js index ad783613..4ec285f0 100644 --- a/client/__tests__/e2e/data.js +++ b/client/__tests__/e2e/data.js @@ -4,7 +4,7 @@ export const datasets = { dataframe: { nObs: "2638", nVar: "1838", - type: "float32" + type: "float32", }, categorical: { louvain: { @@ -15,47 +15,47 @@ export const datasets = { "Dendritic cells": "37", "FCGR3A+ Monocytes": "150", Megakaryocytes: "15", - "NK cells": "154" - } + "NK cells": "154", + }, }, continuous: { n_genes: "int32", percent_mito: "float32", - n_counts: "float32" + n_counts: "float32", }, cellsets: { lasso: [ { "coordinates-as-percent": { x1: 0.1, y1: 0.25, x2: 0.7, y2: 0.75 }, - count: "1181" - } + count: "1181", + }, ], categorical: [ { metadata: "louvain", values: ["B cells", "Megakaryocytes"], - count: "357" - } + count: "357", + }, ], continuous: [ { metadata: "n_genes", "coordinates-as-percent": { x1: 0.25, y1: 0.5, x2: 0.55, y2: 0.5 }, - count: "1537" - } - ] + count: "1537", + }, + ], }, diffexp: { cellset1: [ - { kind: "categorical", metadata: "louvain", values: ["B cells"] } + { kind: "categorical", metadata: "louvain", values: ["B cells"] }, ], cellset2: [ { kind: "categorical", metadata: "louvain", - values: ["CD4 T cells", "NK cells"] - } + values: ["CD4 T cells", "NK cells"], + }, ], "gene-results": [ "HLA-DRB1", @@ -67,21 +67,21 @@ export const datasets = { "HLA-DQB1", "MS4A1", "IL32", - "CD37" - ] + "CD37", + ], }, genes: { bulkadd: ["S100A8", "FCGR3A", "LGALS2", "GSTP1"], - search: "ACD" + search: "ACD", }, subset: { cellset1: [ { kind: "categorical", metadata: "louvain", - values: ["B cells", "Megakaryocytes"] - } + values: ["B cells", "Megakaryocytes"], + }, ], count: "357", categorical: { @@ -93,27 +93,27 @@ export const datasets = { "Dendritic cells": "0", "FCGR3A+ Monocytes": "0", Megakaryocytes: "15", - "NK cells": "0" - } + "NK cells": "0", + }, }, lasso: { "coordinates-as-percent": { x1: 0.25, y1: 0.05, x2: 0.75, y2: 0.55 }, - count: "329" - } + count: "329", + }, }, scatter: { - genes: { x: "S100A8", y: "FCGR3A" } + genes: { x: "S100A8", y: "FCGR3A" }, }, pan: { - "coordinates-as-percent": { x1: 0.75, y1: 0.75, x2: 0.35, y2: 0.35 } + "coordinates-as-percent": { x1: 0.75, y1: 0.75, x2: 0.35, y2: 0.35 }, }, features: { panzoom: { lasso: { "coordinates-as-percent": { x1: 0.3, y1: 0.3, x2: 0.5, y2: 0.5 }, - count: "24" - } - } + count: "24", + }, + }, }, categoryLabel: { lasso: { @@ -122,17 +122,17 @@ export const datasets = { newCount: { bySubsetConfig: { false: "600", - true: "591" - } - } + true: "591", + }, + }, }, annotationsFromFile: { count: { bySubsetConfig: { false: "1161", - true: "856" - } - } + true: "856", + }, + }, }, clip: { min: "30", @@ -141,7 +141,7 @@ export const datasets = { gene: "S100A8", "coordinates-as-percent": { x1: 0.25, y1: 0.5, x2: 0.55, y2: 0.5 }, count: "386", - "gene-cell-count": "416" - } - } + "gene-cell-count": "416", + }, + }, }; diff --git a/client/__tests__/e2e/e2e.test.js b/client/__tests__/e2e/e2e.test.js index 5477c8d5..1710da9c 100644 --- a/client/__tests__/e2e/e2e.test.js +++ b/client/__tests__/e2e/e2e.test.js @@ -24,7 +24,9 @@ afterAll(() => { describe("did launch", () => { test("page launched", async () => { - const element = await utils.getOneElementInnerHTML("[data-testid='header']"); + const element = await utils.getOneElementInnerHTML( + "[data-testid='header']" + ); expect(element).toBe(data.title); }); }); @@ -32,7 +34,9 @@ describe("did launch", () => { describe("metadata loads", () => { test("categories and values from dataset appear", async () => { for (const label in data.categorical) { - const categoryName = await utils.getOneElementInnerText(`[data-testid="category-${label}"]`); + const categoryName = await utils.getOneElementInnerText( + `[data-testid="category-${label}"]` + ); expect(categoryName).toMatch(label); await utils.clickOn(`${label}:category-expand`); const categories = await cxgActions.getAllCategoriesAndCounts(label); @@ -50,7 +54,6 @@ describe("metadata loads", () => { await utils.waitByID(`histogram-${label}`); } }); - }); describe("cell selection", () => { @@ -81,7 +84,9 @@ describe("cell selection", () => { await utils.clickOn(`${cellset.metadata}:category-expand`); await utils.clickOn(`${cellset.metadata}:category-select`); for (const val of cellset.values) { - await utils.clickOn(`categorical-value-select-${cellset.metadata}-${val}`); + await utils.clickOn( + `categorical-value-select-${cellset.metadata}-${val}` + ); } const cellCount = await cxgActions.cellSet(1); expect(cellCount).toBe(cellset.count); @@ -103,12 +108,16 @@ describe("cell selection", () => { }); describe("gene entry", () => { - test("search for single gene", async () => cxgActions.addGeneToSearch(data.genes.search)); + test("search for single gene", async () => + cxgActions.addGeneToSearch(data.genes.search)); test("bulk add genes", async () => { const testGenes = data.genes.bulkadd; await cxgActions.bulkAddGenes(testGenes); - const allHistograms = await cxgActions.getAllHistograms("histogram-user-gene", testGenes); + const allHistograms = await cxgActions.getAllHistograms( + "histogram-user-gene", + testGenes + ); expect(allHistograms).toEqual(expect.arrayContaining(testGenes)); expect(allHistograms.length).toEqual(testGenes.length); }); @@ -172,11 +181,19 @@ describe("subset", () => { const userDefinedGenes = data.genes.bulkadd; const diffExpGenes = data.diffexp["gene-results"]; await cxgActions.bulkAddGenes(userDefinedGenes); - const userDefinedHistograms = await cxgActions.getAllHistograms("histogram-user-gene", userDefinedGenes); - expect(userDefinedHistograms).toEqual(expect.arrayContaining(userDefinedGenes)); - await cxgActions.subset({x1: 0.15, y1: 0.10, x2: 0.98, y2: 0.98}); + const userDefinedHistograms = await cxgActions.getAllHistograms( + "histogram-user-gene", + userDefinedGenes + ); + expect(userDefinedHistograms).toEqual( + expect.arrayContaining(userDefinedGenes) + ); + await cxgActions.subset({ x1: 0.15, y1: 0.1, x2: 0.98, y2: 0.98 }); await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2); - const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes); + const diffExpHistograms = await cxgActions.getAllHistograms( + "histogram-diffexp", + diffExpGenes + ); expect(diffExpHistograms).toEqual(expect.arrayContaining(diffExpGenes)); await utils.clickOn("reset-subset-button"); const expected = [].concat(userDefinedGenes, diffExpGenes); @@ -184,26 +201,38 @@ describe("subset", () => { "histogram-user-gene", expected ); - expect(userDefinedHistogramsAfterSubset).toEqual(expect.arrayContaining(expected)); + expect(userDefinedHistogramsAfterSubset).toEqual( + expect.arrayContaining(expected) + ); }); test("subset selection appends the top diff exp genes to user defined genes", async () => { const userDefinedGenes = data.genes.bulkadd; const diffExpGenes = data.diffexp["gene-results"]; await cxgActions.bulkAddGenes(userDefinedGenes); - const userDefinedHistograms = await cxgActions.getAllHistograms("histogram-user-gene", userDefinedGenes); - expect(userDefinedHistograms).toEqual(expect.arrayContaining(userDefinedGenes)); - await cxgActions.subset({x1: 0.15, y1: 0.10, x2: 0.98, y2: 0.98}); + const userDefinedHistograms = await cxgActions.getAllHistograms( + "histogram-user-gene", + userDefinedGenes + ); + expect(userDefinedHistograms).toEqual( + expect.arrayContaining(userDefinedGenes) + ); + await cxgActions.subset({ x1: 0.15, y1: 0.1, x2: 0.98, y2: 0.98 }); await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2); - const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes); + const diffExpHistograms = await cxgActions.getAllHistograms( + "histogram-diffexp", + diffExpGenes + ); expect(diffExpHistograms).toEqual(expect.arrayContaining(diffExpGenes)); - await cxgActions.subset({x1: 0.16, y1: 0.11, x2: 0.97, y2: 0.97}); + await cxgActions.subset({ x1: 0.16, y1: 0.11, x2: 0.97, y2: 0.97 }); const expected = [].concat(userDefinedGenes, diffExpGenes); const userDefinedHistogramsAfterSubset = await cxgActions.getAllHistograms( "histogram-user-gene", expected ); - expect(userDefinedHistogramsAfterSubset).toEqual(expect.arrayContaining(expected)); + expect(userDefinedHistogramsAfterSubset).toEqual( + expect.arrayContaining(expected) + ); }); }); diff --git a/client/__tests__/e2e/e2eAnnotations.test.js b/client/__tests__/e2e/e2eAnnotations.test.js index 3993dc99..6da0c42e 100644 --- a/client/__tests__/e2e/e2eAnnotations.test.js +++ b/client/__tests__/e2e/e2eAnnotations.test.js @@ -13,14 +13,13 @@ beforeAll(async () => { }); afterAll(() => { - if (browser !== undefined) browser.close() + if (browser !== undefined) browser.close(); }); describe.each([ - {withSubset: true, tag: "subset"}, - {withSubset: false, tag: "whole"} + { withSubset: true, tag: "subset" }, + { withSubset: false, tag: "whole" }, ])("annotations", (config) => { - const perTestCategoryName = "per-test-category"; const perTestLabelName = "per-test-label"; @@ -31,7 +30,8 @@ describe.each([ // setup the test fixtures await actions.createCategory(perTestCategoryName); await actions.createLabel(perTestCategoryName, perTestLabelName); - if (config.withSubset) await actions.subset({x1: 0.10, y1: 0.10, x2: 0.80, y2: 0.80}); + if (config.withSubset) + await actions.subset({ x1: 0.1, y1: 0.1, x2: 0.8, y2: 0.8 }); await utils.waitByClass("autosave-complete"); }); @@ -74,7 +74,11 @@ describe.each([ test("rename a label", async () => { const newLabelName = "my-cool-new-label"; await assertLabelDoesNotExist(perTestCategoryName, newLabelName); - await actions.renameLabel(perTestCategoryName, perTestLabelName, newLabelName); + await actions.renameLabel( + perTestCategoryName, + perTestLabelName, + newLabelName + ); await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName); await assertLabelExists(perTestCategoryName, newLabelName); }); @@ -83,8 +87,10 @@ describe.each([ const categoryName = "cluster-test"; const labelName = "four"; await actions.expandCategory(categoryName); - const result = await utils.waitByID(`categorical-value-count-${categoryName}-${labelName}`); - expect(await result.evaluate(node => node.innerText)).toBe( + const result = await utils.waitByID( + `categorical-value-count-${categoryName}-${labelName}` + ); + expect(await result.evaluate((node) => node.innerText)).toBe( data.annotationsFromFile.count.bySubsetConfig[config.withSubset] ); }); @@ -101,11 +107,17 @@ describe.each([ lassoSelection.end, true ); - await utils.waitByID("lasso-element", {visible: true}); - await utils.clickOn(`${perTestCategoryName}:${perTestLabelName}:see-actions`); - await utils.clickOn(`${perTestCategoryName}:${perTestLabelName}:add-current-selection-to-this-label`); - const result = await utils.waitByID(`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`); - expect(await result.evaluate(node => node.innerText)).toBe( + await utils.waitByID("lasso-element", { visible: true }); + await utils.clickOn( + `${perTestCategoryName}:${perTestLabelName}:see-actions` + ); + await utils.clickOn( + `${perTestCategoryName}:${perTestLabelName}:add-current-selection-to-this-label` + ); + const result = await utils.waitByID( + `categorical-value-count-${perTestCategoryName}-${perTestLabelName}` + ); + expect(await result.evaluate((node) => node.innerText)).toBe( data.categoryLabel.newCount.bySubsetConfig[config.withSubset] ); }); @@ -170,7 +182,11 @@ describe.each([ test("undo/redo label rename", async () => { const newLabelName = `label-renamed-undo-${config.tag}`; await assertLabelDoesNotExist(perTestCategoryName, newLabelName); - await actions.renameLabel(perTestCategoryName, perTestLabelName, newLabelName); + await actions.renameLabel( + perTestCategoryName, + perTestLabelName, + newLabelName + ); await assertLabelExists(perTestCategoryName, newLabelName); await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName); await utils.clickOn("undo"); @@ -183,14 +199,16 @@ describe.each([ async function assertCategoryExists(categoryName) { const handle = await utils.waitByID(`${categoryName}:category-expand`); - const result = await handle.evaluate(node => node.innerText); + const result = await handle.evaluate((node) => node.innerText); // slice beginning and end of category name result to account for truncation of long names expect(result.slice(0, 10)).toBe(categoryName.slice(0, 10)); expect(result.slice(-10)).toBe(categoryName.slice(-10)); } async function assertCategoryDoesNotExist(categoryName) { - const result = await page.$(`[data-testid='${categoryName}:category-expand']`); + const result = await page.$( + `[data-testid='${categoryName}:category-expand']` + ); expect(result).toBeNull(); } @@ -198,13 +216,17 @@ describe.each([ const category = await utils.waitByID(`${categoryName}:category-expand`); expect(category).not.toBeNull(); await actions.expandCategory(categoryName); - const previous = await utils.waitByID(`categorical-value-${categoryName}-${labelName}`); - expect(await previous.evaluate(node => node.innerText)).toBe(labelName); + const previous = await utils.waitByID( + `categorical-value-${categoryName}-${labelName}` + ); + expect(await previous.evaluate((node) => node.innerText)).toBe(labelName); } async function assertLabelDoesNotExist(categoryName, labelName) { await actions.expandCategory(categoryName); - const result = await page.$(`[data-testid='categorical-value-${categoryName}-${labelName}']`); + const result = await page.$( + `[data-testid='categorical-value-${categoryName}-${labelName}']` + ); expect(result).toBeNull(); } @@ -212,10 +234,10 @@ describe.each([ try { const category = await page.waitForSelector( `[data-testid='${categoryName}:category-expand']`, - {timeout: 200} + { timeout: 200 } ); if (category !== null) return await actions.deleteCategory(categoryName); } catch {} - return null + return null; } }); diff --git a/client/__tests__/e2e/e2eJestConfig.json b/client/__tests__/e2e/e2eJestConfig.json index 04410014..585d59f0 100644 --- a/client/__tests__/e2e/e2eJestConfig.json +++ b/client/__tests__/e2e/e2eJestConfig.json @@ -1,9 +1,5 @@ { "preset": "jest-puppeteer", - "testMatch": [ - "**/__tests__/**/?(*.)(spec|test).js?(x)" - ], - "setupFiles": [ - "../setupMissingGlobals.js" - ] + "testMatch": ["**/__tests__/**/?(*.)(spec|test).js?(x)"], + "setupFiles": ["../setupMissingGlobals.js"] } diff --git a/client/__tests__/e2e/feature.test.js b/client/__tests__/e2e/feature.test.js index 8573ce5a..0fed000a 100644 --- a/client/__tests__/e2e/feature.test.js +++ b/client/__tests__/e2e/feature.test.js @@ -29,9 +29,9 @@ beforeAll(async () => { page = await browser.newPage(); await page.setViewport(browserViewport); if (DEV || DEBUG) { - page.on("console", msg => console.log(`PAGE LOG: ${msg.text()}`)); + page.on("console", (msg) => console.log(`PAGE LOG: ${msg.text()}`)); } - page.on("pageerror", err => { + page.on("pageerror", (err) => { throw new Error(`Console error: ${err}`); }); utils = puppeteerUtils(page); diff --git a/client/__tests__/e2e/puppeteerUtils.js b/client/__tests__/e2e/puppeteerUtils.js index 49b21f2b..c72a865b 100644 --- a/client/__tests__/e2e/puppeteerUtils.js +++ b/client/__tests__/e2e/puppeteerUtils.js @@ -1,4 +1,4 @@ -export const puppeteerUtils = page => ({ +export const puppeteerUtils = (page) => ({ async waitByID(testId, props = {}) { return page.waitForSelector(`[data-testid='${testId}']`, props); }, @@ -9,13 +9,13 @@ export const puppeteerUtils = page => ({ async waitForAllByIds(testIds) { await Promise.all( - testIds.map(testId => page.waitForSelector(`[data-testid='${testId}']`)) + testIds.map((testId) => page.waitForSelector(`[data-testid='${testId}']`)) ); }, async getAllByClass(testClass) { - return page.$$eval(`[data-testclass=${testClass}]`, eles => - eles.map(ele => ele.dataset.testid) + return page.$$eval(`[data-testclass=${testClass}]`, (eles) => + eles.map((ele) => ele.dataset.testid) ); }, @@ -52,18 +52,18 @@ export const puppeteerUtils = page => ({ async getOneElementInnerHTML(selector) { await page.waitForSelector(selector); - return page.$eval(selector, el => el.innerHTML); + return page.$eval(selector, (el) => el.innerHTML); }, async getOneElementInnerText(selector) { await page.waitForSelector(selector); - return page.$eval(selector, el => el.innerText); + return page.$eval(selector, (el) => el.innerText); }, async getElementCoordinates(testid) { - return page.$eval(`[data-testid='${testid}']`, elem => { + return page.$eval(`[data-testid='${testid}']`, (elem) => { const { left, top } = elem.getBoundingClientRect(); return [left, top]; }); - } + }, }); diff --git a/client/__tests__/e2e/testBrowser.js b/client/__tests__/e2e/testBrowser.js index 0ae93a4b..8aa57bca 100644 --- a/client/__tests__/e2e/testBrowser.js +++ b/client/__tests__/e2e/testBrowser.js @@ -7,41 +7,48 @@ export async function setupTestBrowser() { const browserViewport = { width: 1280, height: 960 }; const browserParams = DEV ? { - headless: false, - slowMo: 5, - args: [ `--window-size=${browserViewport.width},${browserViewport.height}`] - } + headless: false, + slowMo: 5, + args: [ + `--window-size=${browserViewport.width},${browserViewport.height}`, + ], + } : DEBUG - ? { + ? { headless: false, slowMo: 100, devtools: true, - args: [ `--window-size=${browserViewport.width + 560},${browserViewport.height}`] + args: [ + `--window-size=${browserViewport.width + 560},${ + browserViewport.height + }`, + ], } - : { - args: [ `--window-size=${browserViewport.width},${browserViewport.height}`] + : { + args: [ + `--window-size=${browserViewport.width},${browserViewport.height}`, + ], }; const browser = await puppeteer.launch(browserParams); - const page = await browser.pages().then(pages => pages[0]); + const page = await browser.pages().then((pages) => pages[0]); await page.setViewport(browserViewport); if (DEV || DEBUG) { - page.on("console", async msg => { + page.on("console", async (msg) => { // If there is a console.error but an error is not thrown, this will ensure the test fails if (msg.type() === "error") { const errorMsgText = await Promise.all( // TODO can we do this without internal properties? - msg.args().map(arg => arg._remoteObject.description) + msg.args().map((arg) => arg._remoteObject.description) ); throw new Error(`Console error: ${errorMsgText}`); } console.log(`PAGE LOG: ${msg.text()}`); }); } - page.on("pageerror", err => { + page.on("pageerror", (err) => { throw new Error(`Console error: ${err}`); }); const utils = puppeteerUtils(page); const cxgActions = cellxgeneActions(page, utils); return [browser, page, utils, cxgActions]; } - diff --git a/client/__tests__/reducers/cascade.test.js b/client/__tests__/reducers/cascade.test.js index 5395025b..a61e579e 100644 --- a/client/__tests__/reducers/cascade.test.js +++ b/client/__tests__/reducers/cascade.test.js @@ -26,7 +26,7 @@ describe("cascade", () => { expect(nextSharedState).toStrictEqual({}); expect(prevSharedState).toBe(topLevelState); return 0; - } + }, ], [ "bar", @@ -36,8 +36,8 @@ describe("cascade", () => { expect(nextSharedState).toStrictEqual({ foo: 0 }); expect(prevSharedState).toBe(topLevelState); return 99; - } - ] + }, + ], ]); const nextState = reducer(topLevelState, topLevelAction); diff --git a/client/__tests__/reducers/undoable.test.js b/client/__tests__/reducers/undoable.test.js index 40754e1e..5e27b5af 100644 --- a/client/__tests__/reducers/undoable.test.js +++ b/client/__tests__/reducers/undoable.test.js @@ -23,7 +23,7 @@ describe("create", () => { describe("undo", () => { test("expected state modifications", () => { const initialState = { a: 0, b: 1000 }; - const reducer = state => { + const reducer = (state) => { return { a: state.a + 1, b: state.b + 1 }; }; const undoableReducer = undoable(reducer, ["a"]); @@ -43,7 +43,7 @@ describe("undo", () => { describe("redo", () => { const initialState = { a: 0, b: 1000 }; - const reducer = state => { + const reducer = (state) => { return { a: state.a + 1, b: state.b + 1 }; }; let UR; @@ -58,7 +58,7 @@ describe("redo", () => { // verify undo->redo reverts state. const s2 = UR(UR(s1, { type: "@@undoable/undo" }), { - type: "@@undoable/redo" + type: "@@undoable/redo", }); expect(s2).toMatchObject({ a: 1, b: 1001 }); diff --git a/client/__tests__/util/actionHelpers.test.js b/client/__tests__/util/actionHelpers.test.js index 08d91b70..e6ab9da3 100644 --- a/client/__tests__/util/actionHelpers.test.js +++ b/client/__tests__/util/actionHelpers.test.js @@ -13,16 +13,16 @@ describe("rangeEncodeIndices", () => { expect(rangeEncodeIndices([1, 9, 432], 10, true)).toMatchObject([ 1, 9, - 432 + 432, ]); expect(rangeEncodeIndices([1, 9, 432], 10, false)).toMatchObject([ 1, 9, - 432 + 432, ]); - expect(rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, true)).toMatchObject( - [[0, 3], [9, 10], 432] - ); + expect( + rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, true) + ).toMatchObject([[0, 3], [9, 10], 432]); expect( rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, false) ).toMatchObject([[0, 3], [9, 10], 432]); @@ -34,7 +34,10 @@ describe("rangeEncodeIndices", () => { ).toMatchObject([[3, 7], [10, 12], 99]); expect( rangeEncodeIndices([3, 4, 5, 6, 7, 10, 11, 12], 3, false) - ).toMatchObject([[3, 7], [10, 12]]); + ).toMatchObject([ + [3, 7], + [10, 12], + ]); expect( rangeEncodeIndices([0, 3, 4, 5, 6, 7, 10, 11, 12], 3, false) ).toMatchObject([0, [3, 7], [10, 12]]); diff --git a/client/__tests__/util/centroid.test.js b/client/__tests__/util/centroid.test.js index fd1588fb..28467cde 100644 --- a/client/__tests__/util/centroid.test.js +++ b/client/__tests__/util/centroid.test.js @@ -31,7 +31,7 @@ describe("centroid", () => { ...Universe.addObsLayout( universe, Universe.matrixFBSToDataframe(REST.layoutObs) - ) + ), }; world = World.createWorldFromEntireUniverse(universe); @@ -61,10 +61,10 @@ describe("centroid", () => { // This expected result assumes that all cells belong in all categorical values inside of sample response const expectedResult = [ quantile([0.5], world.obsLayout.col("umap_0").asArray())[0], - quantile([0.5], world.obsLayout.col("umap_1").asArray())[0] + quantile([0.5], world.obsLayout.col("umap_1").asArray())[0], ]; - centroidResult.forEach(coordinate => { + centroidResult.forEach((coordinate) => { expect(coordinate).toEqual(expectedResult); }); }); @@ -86,10 +86,10 @@ describe("centroid", () => { // This expected result assumes that all cells belong in all categorical values inside of sample response const expectedResult = [ quantile([0.5], world.obsLayout.col("umap_0").asArray())[0], - quantile([0.5], world.obsLayout.col("umap_1").asArray())[0] + quantile([0.5], world.obsLayout.col("umap_1").asArray())[0], ]; - centroidResult.forEach(coordinate => { + centroidResult.forEach((coordinate) => { expect(coordinate).toEqual(expectedResult); }); }); diff --git a/client/__tests__/util/dataframe/dataframe.test.js b/client/__tests__/util/dataframe/dataframe.test.js index f489f132..3ad843a9 100644 --- a/client/__tests__/util/dataframe/dataframe.test.js +++ b/client/__tests__/util/dataframe/dataframe.test.js @@ -53,7 +53,7 @@ describe("simple data access", () => { [4, 2], [ new Float64Array([0.0, Number.NaN, Number.POSITIVE_INFINITY, 3.14159]), - ["red", "blue", "green", "nan"] + ["red", "blue", "green", "nan"], ], new Dataframe.DenseInt32Index([3, 2, 1, 0]), new Dataframe.KeyIndex(["numbers", "colors"]) @@ -136,7 +136,7 @@ describe("dataframe subsetting", () => { new Int32Array([0, 1, 2]), ["A", "B", "C"], new Float32Array([4.4, 5.5, 6.6]), - ["red", "green", "blue"] + ["red", "green", "blue"], ], null, new Dataframe.KeyIndex(["int32", "string", "float32", "colors"]) @@ -258,7 +258,7 @@ describe("dataframe subsetting", () => { new Int32Array([0, 1, 2]), ["A", "B", "C"], new Float32Array([4.4, 5.5, 6.6]), - ["red", "green", "blue"] + ["red", "green", "blue"], ], new Dataframe.DenseInt32Index([2, 4, 6]), new Dataframe.KeyIndex(["int32", "string", "float32", "colors"]) @@ -283,7 +283,7 @@ describe("dataframe factories", () => { [ new Array(3).fill(0), new Int16Array(3).fill(99), - new Float64Array(3).fill(1.1) + new Float64Array(3).fill(1.1), ] ); @@ -323,7 +323,7 @@ describe("dataframe factories", () => { [2, 2], [ ["red", "blue"], - [true, false] + [true, false], ], null, new Dataframe.KeyIndex(["colors", "bools"]) @@ -346,7 +346,7 @@ describe("dataframe factories", () => { [2, 2], [ ["red", "blue"], - [true, false] + [true, false], ], null, new Dataframe.DenseInt32Index([74, 75]) @@ -371,7 +371,7 @@ describe("dataframe factories", () => { [2, 2], [ ["red", "blue"], - [true, false] + [true, false], ], null, new Dataframe.DenseInt32Index([74, 75]) @@ -396,7 +396,7 @@ describe("dataframe factories", () => { [2, 2], [ ["red", "blue"], - [true, false] + [true, false], ], null, null @@ -421,7 +421,7 @@ describe("dataframe factories", () => { [2, 2], [ ["red", "blue"], - [true, false] + [true, false], ], null, null @@ -479,7 +479,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["colors", "bools", "numbers"]) @@ -553,7 +553,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["colors", "bools", "numbers"]) @@ -595,7 +595,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["colors", "bools", "numbers"]) @@ -618,7 +618,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["colors", "bools", "numbers"]) @@ -641,7 +641,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, null @@ -665,7 +665,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, null @@ -689,7 +689,7 @@ describe("dataframe factories", () => { [ ["red", "blue"], [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.DenseInt32Index([102, 101, 100]) @@ -715,7 +715,7 @@ describe("dataframe factories", () => { [ new Array(3).fill(0), new Int16Array(3).fill(99), - new Float64Array(3).fill(1.1) + new Float64Array(3).fill(1.1), ] ); const dfB = dfA.mapColumns((col, idx) => { @@ -760,7 +760,7 @@ describe("dataframe factories", () => { [2, 2], [ [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["A", "B"]) @@ -781,7 +781,7 @@ describe("dataframe col", () => { [2, 2], [ [true, false], - [1, 0] + [1, 0], ], null, new Dataframe.KeyIndex(["A", "B"]) diff --git a/client/__tests__/util/dataframe/histogram.test.js b/client/__tests__/util/dataframe/histogram.test.js index 1549d27d..ce4c4943 100644 --- a/client/__tests__/util/dataframe/histogram.test.js +++ b/client/__tests__/util/dataframe/histogram.test.js @@ -14,7 +14,7 @@ describe("Dataframe column histogram", () => { new Map([ ["n1", new Map([["c1", 1]])], ["n2", new Map([["c2", 1]])], - ["n3", new Map([["c3", 1]])] + ["n3", new Map([["c3", 1]])], ]) ); // memoized? @@ -31,7 +31,11 @@ describe("Dataframe column histogram", () => { const h1 = df.col("value").histogram(3, [0, 2], df.col("name")); expect(h1).toMatchObject( - new Map([["n1", [1, 0, 0]], ["n2", [0, 1, 0]], ["n3", [0, 0, 1]]]) + new Map([ + ["n1", [1, 0, 0]], + ["n2", [0, 1, 0]], + ["n3", [0, 0, 1]], + ]) ); // memoized? expect(df.col("value").histogram(3, [0, 2], df.col("name"))).toMatchObject( @@ -48,7 +52,13 @@ describe("Dataframe column histogram", () => { ); const h1 = df.col("cat").histogram(); - expect(h1).toMatchObject(new Map([["c1", 1], ["c2", 1], ["c3", 1]])); + expect(h1).toMatchObject( + new Map([ + ["c1", 1], + ["c2", 1], + ["c3", 1], + ]) + ); // memoized? expect(df.col("value").histogram(3, [0, 2])).toMatchObject(h1); }); @@ -87,7 +97,7 @@ describe("Dataframe column histogram", () => { 0, 0, 0, - 2 + 2, ]); }); }); diff --git a/client/__tests__/util/dataframe/summarize.test.js b/client/__tests__/util/dataframe/summarize.test.js index 702d0fae..ec98d7be 100644 --- a/client/__tests__/util/dataframe/summarize.test.js +++ b/client/__tests__/util/dataframe/summarize.test.js @@ -13,7 +13,7 @@ describe("Dataframe column summary", () => { categorical: true, categories: [], categoryCounts: new Map(), - numCategories: 0 + numCategories: 0, }) ); }); @@ -27,7 +27,7 @@ describe("Dataframe column summary", () => { [true], new Float32Array([39.3]), new Int32Array([99]), - [1] + [1], ], null, new Dataframe.KeyIndex([ @@ -36,7 +36,7 @@ describe("Dataframe column summary", () => { "nameBoolean", "nameFloat32", "nameInt32", - "nameCategorical" + "nameCategorical", ]) ); @@ -45,7 +45,7 @@ describe("Dataframe column summary", () => { categorical: true, categories: ["n1"], categoryCounts: new Map([["n1", 1]]), - numCategories: 1 + numCategories: 1, }) ); expect(df.icol(1).summarize()).toEqual( @@ -53,7 +53,7 @@ describe("Dataframe column summary", () => { categorical: true, categories: ["hi"], categoryCounts: new Map([["hi", 1]]), - numCategories: 1 + numCategories: 1, }) ); expect(df.icol(2).summarize()).toEqual( @@ -61,7 +61,7 @@ describe("Dataframe column summary", () => { categorical: true, categories: [true], categoryCounts: new Map([[true, 1]]), - numCategories: 1 + numCategories: 1, }) ); expect(df.icol(3).summarize()).toEqual( @@ -71,7 +71,7 @@ describe("Dataframe column summary", () => { max: float32Conversion(39.3), nan: 0, ninf: 0, - pinf: 0 + pinf: 0, }) ); expect(df.icol(4).summarize()).toEqual( @@ -81,7 +81,7 @@ describe("Dataframe column summary", () => { max: 99, nan: 0, ninf: 0, - pinf: 0 + pinf: 0, }) ); expect(df.icol(5).summarize()).toEqual( @@ -89,7 +89,7 @@ describe("Dataframe column summary", () => { categorical: true, categories: [1], categoryCounts: new Map([[1, 1]]), - numCategories: 1 + numCategories: 1, }) ); }); @@ -103,7 +103,7 @@ describe("Dataframe column summary", () => { [false, true, true], new Float32Array([39.3, 39.3, 0]), new Int32Array([99, 99, 99]), - [1, false, "0"] + [1, false, "0"], ], null, new Dataframe.KeyIndex([ @@ -112,7 +112,7 @@ describe("Dataframe column summary", () => { "nameBoolean", "nameFloat32", "nameInt32", - "nameCategorical" + "nameCategorical", ]) ); @@ -120,24 +120,34 @@ describe("Dataframe column summary", () => { expect.objectContaining({ categorical: true, categories: expect.arrayContaining(["n0", "n1", "n2"]), - categoryCounts: new Map([["n0", 1], ["n1", 1], ["n2", 1]]), - numCategories: 3 + categoryCounts: new Map([ + ["n0", 1], + ["n1", 1], + ["n2", 1], + ]), + numCategories: 3, }) ); expect(df.icol(1).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining(["hi", "bye"]), - categoryCounts: new Map([["hi", 2], ["bye", 1]]), - numCategories: 2 + categoryCounts: new Map([ + ["hi", 2], + ["bye", 1], + ]), + numCategories: 2, }) ); expect(df.icol(2).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining([true, false]), - categoryCounts: new Map([[true, 2], [false, 1]]), - numCategories: 2 + categoryCounts: new Map([ + [true, 2], + [false, 1], + ]), + numCategories: 2, }) ); expect(df.icol(3).summarize()).toEqual( @@ -147,7 +157,7 @@ describe("Dataframe column summary", () => { max: float32Conversion(39.3), nan: 0, ninf: 0, - pinf: 0 + pinf: 0, }) ); expect(df.icol(4).summarize()).toEqual( @@ -157,15 +167,19 @@ describe("Dataframe column summary", () => { max: 99, nan: 0, ninf: 0, - pinf: 0 + pinf: 0, }) ); expect(df.icol(5).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining([1, false, "0"]), - categoryCounts: new Map([[1, 1], [false, 1], ["0", 1]]), - numCategories: 3 + categoryCounts: new Map([ + [1, 1], + [false, 1], + ["0", 1], + ]), + numCategories: 3, }) ); }); @@ -181,10 +195,10 @@ describe("Dataframe column summary", () => { 39.3, Number.NEGATIVE_INFINITY, Number.NaN, - Number.POSITIVE_INFINITY + Number.POSITIVE_INFINITY, ]), new Int32Array([99, 99, 99, 99]), - [1, false, "0", "0"] + [1, false, "0", "0"], ], null, new Dataframe.KeyIndex([ @@ -193,7 +207,7 @@ describe("Dataframe column summary", () => { "nameBoolean", "nameFloat32", "nameInt32", - "nameCategorical" + "nameCategorical", ]) ); @@ -201,24 +215,34 @@ describe("Dataframe column summary", () => { expect.objectContaining({ categorical: true, categories: expect.arrayContaining(["n0", "n1", "n2"]), - categoryCounts: new Map([["n0", 1], ["n1", 1], ["n2", 2]]), - numCategories: 3 + categoryCounts: new Map([ + ["n0", 1], + ["n1", 1], + ["n2", 2], + ]), + numCategories: 3, }) ); expect(df.icol(1).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining(["hi", "bye"]), - categoryCounts: new Map([["hi", 2], ["bye", 1]]), - numCategories: 2 + categoryCounts: new Map([ + ["hi", 2], + ["bye", 1], + ]), + numCategories: 2, }) ); expect(df.icol(2).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining([true, false]), - categoryCounts: new Map([[true, 2], [false, 1]]), - numCategories: 2 + categoryCounts: new Map([ + [true, 2], + [false, 1], + ]), + numCategories: 2, }) ); expect(df.icol(3).summarize()).toEqual( @@ -228,7 +252,7 @@ describe("Dataframe column summary", () => { max: float32Conversion(39.3), nan: 1, ninf: 1, - pinf: 1 + pinf: 1, }) ); expect(df.icol(4).summarize()).toEqual( @@ -238,15 +262,19 @@ describe("Dataframe column summary", () => { max: 99, nan: 0, ninf: 0, - pinf: 0 + pinf: 0, }) ); expect(df.icol(5).summarize()).toEqual( expect.objectContaining({ categorical: true, categories: expect.arrayContaining([1, false, "0"]), - categoryCounts: new Map([[1, 1], [false, 1], ["0", 1]]), - numCategories: 3 + categoryCounts: new Map([ + [1, 1], + [false, 1], + ["0", 1], + ]), + numCategories: 3, }) ); }); diff --git a/client/__tests__/util/nameCreators.test.js b/client/__tests__/util/nameCreators.test.js index 5c6f462c..99ea0a62 100644 --- a/client/__tests__/util/nameCreators.test.js +++ b/client/__tests__/util/nameCreators.test.js @@ -6,7 +6,7 @@ import { obsAnnoDimensionName, diffexpDimensionName, userDefinedDimensionName, - makeContinuousDimensionName + makeContinuousDimensionName, } from "../../src/util/nameCreators"; describe("nameCreators", () => { @@ -14,25 +14,25 @@ describe("nameCreators", () => { layoutDimensionName, obsAnnoDimensionName, diffexpDimensionName, - userDefinedDimensionName + userDefinedDimensionName, ]; test("check for namespace isolation", () => { const foo = "foo"; - nameCreators.forEach(fn => expect(fn(foo)).not.toBe(foo)); + nameCreators.forEach((fn) => expect(fn(foo)).not.toBe(foo)); const bar = "bar"; - nameCreators.forEach(fn => expect(fn(foo)).not.toBe(fn(bar))); + nameCreators.forEach((fn) => expect(fn(foo)).not.toBe(fn(bar))); - nameCreators.forEach(fn => { - const allOtherFn = nameCreators.filter(elmnt => elmnt !== fn); - allOtherFn.forEach(otherFn => expect(fn(foo)).not.toBe(otherFn(foo))); + nameCreators.forEach((fn) => { + const allOtherFn = nameCreators.filter((elmnt) => elmnt !== fn); + allOtherFn.forEach((otherFn) => expect(fn(foo)).not.toBe(otherFn(foo))); }); }); test("check for legal keys", () => { /* need namespace creators to return strings only */ - nameCreators.forEach(fn => expect(fn("X")).toMatch(/X/)); + nameCreators.forEach((fn) => expect(fn("X")).toMatch(/X/)); }); }); diff --git a/client/__tests__/util/promiseLimit.test.js b/client/__tests__/util/promiseLimit.test.js index 589c4acf..fc6832f6 100644 --- a/client/__tests__/util/promiseLimit.test.js +++ b/client/__tests__/util/promiseLimit.test.js @@ -1,73 +1,73 @@ import { PromiseLimit } from "../../src/util/promiseLimit"; import { range } from "../../src/util/range"; -const delay = t => new Promise((resolve, reject) => setTimeout(resolve, t)); +const delay = (t) => new Promise((resolve, reject) => setTimeout(resolve, t)); describe("PromiseLimit", () => { - test("simple evaluation, concurrency 1", async () => { - const plimit = new PromiseLimit(1); - const result = await Promise.all([ - plimit.add(() => Promise.resolve(1)), - plimit.add(() => Promise.resolve(2)), - plimit.add(() => Promise.resolve(3)), - plimit.add(() => Promise.resolve(4)) - ]); - expect(result).toEqual([1, 2, 3, 4]); - }); + test("simple evaluation, concurrency 1", async () => { + const plimit = new PromiseLimit(1); + const result = await Promise.all([ + plimit.add(() => Promise.resolve(1)), + plimit.add(() => Promise.resolve(2)), + plimit.add(() => Promise.resolve(3)), + plimit.add(() => Promise.resolve(4)), + ]); + expect(result).toEqual([1, 2, 3, 4]); + }); - test("simple evaluation, concurrency > 1", async () => { - const plimit = new PromiseLimit(100); - const result = await Promise.all([ - plimit.add(() => Promise.resolve(1)), - plimit.add(() => Promise.resolve(2)), - plimit.add(() => Promise.resolve(3)), - plimit.add(() => Promise.resolve(4)) - ]); - expect(result).toEqual([1, 2, 3, 4]); - }); + test("simple evaluation, concurrency > 1", async () => { + const plimit = new PromiseLimit(100); + const result = await Promise.all([ + plimit.add(() => Promise.resolve(1)), + plimit.add(() => Promise.resolve(2)), + plimit.add(() => Promise.resolve(3)), + plimit.add(() => Promise.resolve(4)), + ]); + expect(result).toEqual([1, 2, 3, 4]); + }); - test("eval in order of insertion", async () => { - const plimit = new PromiseLimit(100); - let counter = 0; - const result = await Promise.all([ - plimit.add(() => Promise.resolve((counter += 1))), - plimit.add(() => Promise.resolve((counter += 1))), - plimit.add(() => Promise.resolve((counter += 1))), - plimit.add(() => Promise.resolve((counter += 1))) - ]); - expect(result).toEqual([1, 2, 3, 4]); - }); + test("eval in order of insertion", async () => { + const plimit = new PromiseLimit(100); + let counter = 0; + const result = await Promise.all([ + plimit.add(() => Promise.resolve((counter += 1))), + plimit.add(() => Promise.resolve((counter += 1))), + plimit.add(() => Promise.resolve((counter += 1))), + plimit.add(() => Promise.resolve((counter += 1))), + ]); + expect(result).toEqual([1, 2, 3, 4]); + }); - test("obeys concurrency limit", async () => { - const plimit = new PromiseLimit(2); - let running = 0; - let maxRunning = 0; + test("obeys concurrency limit", async () => { + const plimit = new PromiseLimit(2); + let running = 0; + let maxRunning = 0; - const cbfn = async i => { - running = running + 1; - maxRunning = running > maxRunning ? running : maxRunning; - await delay(100); - running = running - 1; - }; + const cbfn = async (i) => { + running = running + 1; + maxRunning = running > maxRunning ? running : maxRunning; + await delay(100); + running = running - 1; + }; - const result = await Promise.all( - range(10).map(i => plimit.add(() => cbfn(i))) - ); - expect(maxRunning).toEqual(2); - }); + const result = await Promise.all( + range(10).map((i) => plimit.add(() => cbfn(i))) + ); + expect(maxRunning).toEqual(2); + }); - test("rejection", async () => { - const plimit = new PromiseLimit(2); - const result = await Promise.all([ - plimit.add(() => Promise.resolve("OK")), - plimit.add(() => Promise.reject("not OK")).catch(e => e), - plimit.add(() => Promise.resolve("OK")), - plimit - .add(() => { - throw new Error("not OK"); - }) - .catch(e => e.message) - ]); - expect(result).toEqual(["OK", "not OK", "OK", "not OK"]); - }); + test("rejection", async () => { + const plimit = new PromiseLimit(2); + const result = await Promise.all([ + plimit.add(() => Promise.resolve("OK")), + plimit.add(() => Promise.reject("not OK")).catch((e) => e), + plimit.add(() => Promise.resolve("OK")), + plimit + .add(() => { + throw new Error("not OK"); + }) + .catch((e) => e.message), + ]); + expect(result).toEqual(["OK", "not OK", "OK", "not OK"]); + }); }); diff --git a/client/__tests__/util/quantile.test.js b/client/__tests__/util/quantile.test.js index b8b49954..b316554c 100644 --- a/client/__tests__/util/quantile.test.js +++ b/client/__tests__/util/quantile.test.js @@ -1,29 +1,29 @@ import quantile from "../../src/util/quantile"; describe("quantile", () => { - test("single q", () => { - const arr = new Float32Array([9, 3, 5, 6, 0]); - expect(quantile([1.0], arr)).toMatchObject([9]); - expect(quantile([0.9], arr)).toMatchObject([9]); - expect(quantile([0.8], arr)).toMatchObject([9]); - expect(quantile([0.7], arr)).toMatchObject([6]); - expect(quantile([0.6], arr)).toMatchObject([6]); - expect(quantile([0.5], arr)).toMatchObject([5]); - expect(quantile([0.4], arr)).toMatchObject([5]); - expect(quantile([0.3], arr)).toMatchObject([3]); - expect(quantile([0.2], arr)).toMatchObject([3]); - expect(quantile([0.1], arr)).toMatchObject([0]); - expect(quantile([0], arr)).toMatchObject([0]); - }); + test("single q", () => { + const arr = new Float32Array([9, 3, 5, 6, 0]); + expect(quantile([1.0], arr)).toMatchObject([9]); + expect(quantile([0.9], arr)).toMatchObject([9]); + expect(quantile([0.8], arr)).toMatchObject([9]); + expect(quantile([0.7], arr)).toMatchObject([6]); + expect(quantile([0.6], arr)).toMatchObject([6]); + expect(quantile([0.5], arr)).toMatchObject([5]); + expect(quantile([0.4], arr)).toMatchObject([5]); + expect(quantile([0.3], arr)).toMatchObject([3]); + expect(quantile([0.2], arr)).toMatchObject([3]); + expect(quantile([0.1], arr)).toMatchObject([0]); + expect(quantile([0], arr)).toMatchObject([0]); + }); - test("multi q", () => { - const arr = new Float32Array([9, 3, 5, 6, 0]); - expect(quantile([0, 0.25, 0.5, 0.75, 1.0], arr)).toMatchObject([ - 0, - 3, - 5, - 6, - 9 - ]); - }); + test("multi q", () => { + const arr = new Float32Array([9, 3, 5, 6, 0]); + expect(quantile([0, 0.25, 0.5, 0.75, 1.0], arr)).toMatchObject([ + 0, + 3, + 5, + 6, + 9, + ]); + }); }); diff --git a/client/__tests__/util/range.test.js b/client/__tests__/util/range.test.js index fac1ade3..5da8821d 100644 --- a/client/__tests__/util/range.test.js +++ b/client/__tests__/util/range.test.js @@ -1,50 +1,48 @@ import { range, rangeFill, linspace } from "../../src/util/range"; describe("range", () => { - test("no defaults", () => { - expect(range(0, 3, 1)).toMatchObject([0, 1, 2]); - }); + test("no defaults", () => { + expect(range(0, 3, 1)).toMatchObject([0, 1, 2]); + }); - test("range(stop)", () => { - expect(range(3)).toMatchObject([0, 1, 2]); - expect(range(0)).toMatchObject([]); - expect(range(1)).toMatchObject([0]); - }); + test("range(stop)", () => { + expect(range(3)).toMatchObject([0, 1, 2]); + expect(range(0)).toMatchObject([]); + expect(range(1)).toMatchObject([0]); + }); - test("range(start,stop)", () => { - expect(range(0, 0)).toMatchObject([]); - expect(range(0, 2)).toMatchObject([0, 1]); - expect(range(4, 8)).toMatchObject([4, 5, 6, 7]); - }); + test("range(start,stop)", () => { + expect(range(0, 0)).toMatchObject([]); + expect(range(0, 2)).toMatchObject([0, 1]); + expect(range(4, 8)).toMatchObject([4, 5, 6, 7]); + }); - test("range(start, stop, step", () => { - expect(range(4, 0, -1)).toMatchObject([4, 3, 2, 1]); - expect(range(0, 4, 2)).toMatchObject([0, 2]); - }); + test("range(start, stop, step", () => { + expect(range(4, 0, -1)).toMatchObject([4, 3, 2, 1]); + expect(range(0, 4, 2)).toMatchObject([0, 2]); + }); }); describe("rangefill", () => { - test("rangeFill(arr)", () => { - expect(rangeFill(new Int32Array(3))).toMatchObject( - new Int32Array([0, 1, 2]) - ); - }); - test("rangeFill(arr, start)", () => { - expect(rangeFill(new Int32Array(2), 1)).toMatchObject( - new Int32Array([1, 2]) - ); - }); - test("rangeFill(arr, start, step)", () => { - expect(rangeFill(new Int32Array(3), 2, -1)).toMatchObject( - new Int32Array([2, 1, 0]) - ); - }); + test("rangeFill(arr)", () => { + expect(rangeFill(new Int32Array(3))).toMatchObject( + new Int32Array([0, 1, 2]) + ); + }); + test("rangeFill(arr, start)", () => { + expect(rangeFill(new Int32Array(2), 1)).toMatchObject( + new Int32Array([1, 2]) + ); + }); + test("rangeFill(arr, start, step)", () => { + expect(rangeFill(new Int32Array(3), 2, -1)).toMatchObject( + new Int32Array([2, 1, 0]) + ); + }); }); describe("linspace", () => { - test("linspace(arr, start, step)", () => { - expect(linspace(0.0, 2.0, 5)).toMatchObject( - [0.0, 0.5, 1.0, 1.5, 2.0] - ); - }); + test("linspace(arr, start, step)", () => { + expect(linspace(0.0, 2.0, 5)).toMatchObject([0.0, 0.5, 1.0, 1.5, 2.0]); + }); }); diff --git a/client/__tests__/util/stateManager/controlsHelpers.test.js b/client/__tests__/util/stateManager/controlsHelpers.test.js index 1e7b1a7a..eed02a14 100644 --- a/client/__tests__/util/stateManager/controlsHelpers.test.js +++ b/client/__tests__/util/stateManager/controlsHelpers.test.js @@ -5,20 +5,23 @@ import { subsetAndResetGeneLists } from "../../../src/util/stateManager/controls import * as globals from "../../../src/globals"; describe("controls helpers", () => { - test("subsetAndResetGeneLists", () => { - const geneList = [...Array(150).keys()].map(() => - Math.random().toString(36).substring(2, 6) // random string of 4 characters + const geneList = [...Array(150).keys()].map( + () => Math.random().toString(36).substring(2, 6) // random string of 4 characters ); const state = { userDefinedGenes: geneList.slice(0, 20), diffexpGenes: geneList.slice(20), }; - const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(state); + const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists( + state + ); expect(globals.maxUserDefinedGenes).toBeLessThan(globals.maxGenes); expect(geneList.length).toBeGreaterThan(globals.maxGenes); expect(newUserDefinedGenes).toHaveLength(globals.maxGenes); - expect(newUserDefinedGenes).toStrictEqual(geneList.slice(0, globals.maxGenes)); + expect(newUserDefinedGenes).toStrictEqual( + geneList.slice(0, globals.maxGenes) + ); expect(newDiffExpGenes).toStrictEqual([]); }); }); diff --git a/client/__tests__/util/stateManager/fbs.test.js b/client/__tests__/util/stateManager/fbs.test.js index 612a2316..c7c639e7 100644 --- a/client/__tests__/util/stateManager/fbs.test.js +++ b/client/__tests__/util/stateManager/fbs.test.js @@ -3,32 +3,32 @@ test FBS encode/decode API */ import { Dataframe, KeyIndex } from "../../../src/util/dataframe"; import { - decodeMatrixFBS, - encodeMatrixFBS + decodeMatrixFBS, + encodeMatrixFBS, } from "../../../src/util/stateManager/matrix"; describe("encode/decode", () => { - test("round trip", () => { - const columns = [ - ["red", "green", "blue"], - new Int32Array(3).fill(0), - new Uint32Array(3).fill(1), - new Float32Array(3).fill(2) - ]; + test("round trip", () => { + const columns = [ + ["red", "green", "blue"], + new Int32Array(3).fill(0), + new Uint32Array(3).fill(1), + new Float32Array(3).fill(2), + ]; - const dfNoColIdx = new Dataframe([3, 4], columns); - const dfA = decodeMatrixFBS(encodeMatrixFBS(dfNoColIdx)); - expect([dfA.nRows, dfA.nCols]).toEqual(dfNoColIdx.dims); - expect(dfA.colIdx).toBeNull(); - expect(dfA.rowIdx).toBeNull(); - expect(dfA.columns).toEqual(columns); + const dfNoColIdx = new Dataframe([3, 4], columns); + const dfA = decodeMatrixFBS(encodeMatrixFBS(dfNoColIdx)); + expect([dfA.nRows, dfA.nCols]).toEqual(dfNoColIdx.dims); + expect(dfA.colIdx).toBeNull(); + expect(dfA.rowIdx).toBeNull(); + expect(dfA.columns).toEqual(columns); - const colIndex = new KeyIndex(["a", "b", "c", "d"]); - const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex); - const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx)); - expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims); - expect(dfB.colIdx).toEqual(colIndex.keys()); - expect(dfB.rowIdx).toBeNull(); - expect(dfB.columns).toEqual(columns); - }); + const colIndex = new KeyIndex(["a", "b", "c", "d"]); + const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex); + const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx)); + expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims); + expect(dfB.colIdx).toEqual(colIndex.keys()); + expect(dfB.rowIdx).toBeNull(); + expect(dfB.columns).toEqual(columns); + }); }); diff --git a/client/__tests__/util/stateManager/sampleResponses.js b/client/__tests__/util/stateManager/sampleResponses.js index 17fb0e8b..9e2041d0 100644 --- a/client/__tests__/util/stateManager/sampleResponses.js +++ b/client/__tests__/util/stateManager/sampleResponses.js @@ -17,13 +17,13 @@ const aConfigResponse = { { method: "POST", path: "/cluster/", available: false }, { method: "POST", path: "/layout/", available: false }, { method: "POST", path: "/diffexp/", available: false }, - { method: "POST", path: "/saveLocal/", available: false } + { method: "POST", path: "/saveLocal/", available: false }, ], displayNames: { engine: "the little engine that could", - dataset: "all your zeros are mine" - } - } + dataset: "all your zeros are mine", + }, + }, }; const aSchemaResponse = { @@ -31,7 +31,7 @@ const aSchemaResponse = { dataframe: { nObs, nVar, - type: "float32" + type: "float32", }, annotations: { obs: { @@ -44,9 +44,9 @@ const aSchemaResponse = { { name: "field4", type: "categorical", - categories: field4Categories - } - ] + categories: field4Categories, + }, + ], }, var: { index: "name", @@ -58,46 +58,46 @@ const aSchemaResponse = { { name: "fieldD", type: "categorical", - categories: fieldDCategories - } - ] - } + categories: fieldDCategories, + }, + ], + }, }, layout: { obs: [{ name: "umap", type: "float32", dims: ["umap_0", "umap_1"] }], - var: [] - } - } + var: [], + }, + }, }; const anAnnotationsObsJSONResponse = { names: ["name", "field1", "field2", "field3", "field4"], data: _() .range(nObs) - .map(idx => [ + .map((idx) => [ idx, `obs${idx}`, 2 * idx, idx + 0.0133, !!(idx & 1), - field4Categories[idx % field4Categories.length] + field4Categories[idx % field4Categories.length], ]) - .value() + .value(), }; const anAnnotationsVarJSONResponse = { names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"], data: _() .range(nVar) - .map(idx => [ + .map((idx) => [ idx, 10 * idx, idx + 2.90143, !!(idx & 1), fieldDCategories[idx % fieldDCategories.length], - `var${idx}` + `var${idx}`, ]) - .value() + .value(), }; function encodeTypedArray(builder, uType, uData) { @@ -120,7 +120,7 @@ function encodeMatrix(columns, colIndex = undefined) { */ const utf8Encoder = new TextEncoder("utf-8"); const builder = new flatbuffers.Builder(1024); - const cols = _.map(columns, carr => { + const cols = _.map(columns, (carr) => { let uType; let tarr; if (_.every(carr, _.isNumber)) { @@ -178,7 +178,7 @@ const anAnnotationsVarFBSResponse = (() => { const aLayoutFBSResponse = (() => { const coords = [ new Float32Array(nObs).fill(Math.random()), - new Float32Array(nObs).fill(Math.random()) + new Float32Array(nObs).fill(Math.random()), ]; return encodeMatrix(coords, ["umap_0", "umap_1"]); })(); @@ -187,8 +187,8 @@ const aDataObsResponse = { var: [2, 4, 29], obs: _() .range(nObs) - .map(idx => [idx, Math.random(), Math.random(), Math.random()]) - .value() + .map((idx) => [idx, Math.random(), Math.random(), Math.random()]) + .value(), }; export { @@ -197,5 +197,5 @@ export { anAnnotationsVarFBSResponse as annotationsVar, anAnnotationsObsFBSResponse as annotationsObs, aSchemaResponse as schema, - aConfigResponse as config + aConfigResponse as config, }; diff --git a/client/__tests__/util/stateManager/universe.test.js b/client/__tests__/util/stateManager/universe.test.js index f647d7e7..76964723 100644 --- a/client/__tests__/util/stateManager/universe.test.js +++ b/client/__tests__/util/stateManager/universe.test.js @@ -43,7 +43,7 @@ describe("createUniverseFromResponse", () => { obsAnnotations: expect.any(Dataframe.Dataframe), varAnnotations: expect.any(Dataframe.Dataframe), obsLayout: expect.any(Dataframe.Dataframe), - varData: expect.any(Dataframe.Dataframe) + varData: expect.any(Dataframe.Dataframe), }) ); @@ -60,7 +60,7 @@ describe("createUniverseFromResponse", () => { ...Universe.addObsLayout( universe, Universe.matrixFBSToDataframe(REST.layoutObs) - ) + ), }; expect(universe).toMatchObject( @@ -71,13 +71,13 @@ describe("createUniverseFromResponse", () => { obsAnnotations: expect.any(Dataframe.Dataframe), varAnnotations: expect.any(Dataframe.Dataframe), obsLayout: expect.any(Dataframe.Dataframe), - varData: expect.any(Dataframe.Dataframe) + varData: expect.any(Dataframe.Dataframe), }) ); expect(universe.obsAnnotations.dims).toEqual([ nObs, - REST.schema.schema.annotations.obs.columns.length + REST.schema.schema.annotations.obs.columns.length, ]); expect(universe.obsLayout.dims).toEqual([nObs, 2]); expect(universe.obsLayout.colIndex.keys()).toEqual( @@ -85,7 +85,7 @@ describe("createUniverseFromResponse", () => { ); expect(universe.varAnnotations.dims).toEqual([ nVar, - REST.schema.schema.annotations.var.columns.length + REST.schema.schema.annotations.var.columns.length, ]); expect(universe.varData.isEmpty()).toBeTruthy(); }); diff --git a/client/__tests__/util/stateManager/world.test.js b/client/__tests__/util/stateManager/world.test.js index 62ea7626..6b6a5bfb 100644 --- a/client/__tests__/util/stateManager/world.test.js +++ b/client/__tests__/util/stateManager/world.test.js @@ -7,7 +7,7 @@ import { DimTypes } from "../../../src/util/typedCrossfilter/crossfilter"; import * as REST from "./sampleResponses"; import { obsAnnoDimensionName, - layoutDimensionName + layoutDimensionName, } from "../../../src/util/nameCreators"; /* @@ -35,7 +35,7 @@ const defaultBigBang = () => { ...Universe.addObsLayout( universe, Universe.matrixFBSToDataframe(REST.layoutObs) - ) + ), }; /* create world */ @@ -50,7 +50,7 @@ const defaultBigBang = () => { return { universe, world, - crossfilter + crossfilter, }; }; @@ -80,8 +80,8 @@ describe("createWorldFromEntireUniverse", () => { clipQuantiles: { min: 0, max: 1 }, unclipped: { obsAnnotations: expect.any(Dataframe.Dataframe), - varData: expect.any(Dataframe.Dataframe) - } + varData: expect.any(Dataframe.Dataframe), + }, }) ); }); @@ -92,7 +92,7 @@ describe("createWorldFromCurrentSelection", () => { const { universe, world: originalWorld, - crossfilter: originalCrossfilter + crossfilter: originalCrossfilter, } = defaultBigBang(); /* mock a selection */ @@ -100,7 +100,7 @@ describe("createWorldFromCurrentSelection", () => { .select(obsAnnoDimensionName("field1"), { mode: "range", lo: 0, hi: 5 }) .select(obsAnnoDimensionName("field3"), { mode: "exact", - values: [false] + values: [false], }); /* create the world from the selection */ @@ -124,7 +124,7 @@ describe("createWorldFromCurrentSelection", () => { }; const matchingIndices = _() .range(universe.nObs) - .filter(idx => matchFilter(universe.obsAnnotations, idx)) + .filter((idx) => matchFilter(universe.obsAnnotations, idx)) .value(); expect(world).toMatchObject( @@ -139,8 +139,8 @@ describe("createWorldFromCurrentSelection", () => { varData: expect.any(Dataframe.Dataframe), unclipped: { obsAnnotations: expect.any(Dataframe.Dataframe), - varData: expect.any(Dataframe.Dataframe) - } + varData: expect.any(Dataframe.Dataframe), + }, }) ); @@ -170,7 +170,7 @@ describe("createObsDimensionMap", () => { const { crossfilter } = defaultBigBang(); const annotationNames = _.map( REST.schema.schema.annotations.obs.columns, - c => c.name + (c) => c.name ); const obsIndexColName = REST.schema.schema.annotations.obs.index; const schemaByObsName = _.keyBy( @@ -178,7 +178,7 @@ describe("createObsDimensionMap", () => { "name" ); expect(crossfilter).toBeDefined(); - annotationNames.forEach(name => { + annotationNames.forEach((name) => { const dim = crossfilter.dimensions[obsAnnoDimensionName(name)]; if (name === obsIndexColName) { expect(dim).toBeUndefined(); diff --git a/client/__tests__/util/typedCrossfilter/bitArray.test.js b/client/__tests__/util/typedCrossfilter/bitArray.test.js index 3a712328..90ad4760 100644 --- a/client/__tests__/util/typedCrossfilter/bitArray.test.js +++ b/client/__tests__/util/typedCrossfilter/bitArray.test.js @@ -187,7 +187,7 @@ describe("fillBySelection", () => { describe("wide bitarray", () => { test.each([9, 30, 31, 32, 33, 54, 63, 64, 65, 127, 128, 129])( "more than %d dimensions", - ndim => { + (ndim) => { /* ensure we move across the uint boundary correctly */ const ba = new BitArray(defaultTestLength); diff --git a/client/__tests__/util/typedCrossfilter/crossfilter.test.js b/client/__tests__/util/typedCrossfilter/crossfilter.test.js index 9fd4e298..a65d2949 100644 --- a/client/__tests__/util/typedCrossfilter/crossfilter.test.js +++ b/client/__tests__/util/typedCrossfilter/crossfilter.test.js @@ -11,7 +11,7 @@ const someData = [ type: "tab", productIDs: ["001"], coords: [0, 0], - nonFinite: 0.0 + nonFinite: 0.0, }, { date: "2011-11-14T16:20:19Z", @@ -21,7 +21,7 @@ const someData = [ type: "tab", productIDs: ["001", "005"], coords: [0.4, 0.4], - nonFinite: Number.NaN + nonFinite: Number.NaN, }, { date: "2011-11-14T16:28:54Z", @@ -31,7 +31,7 @@ const someData = [ type: "visa", productIDs: ["004", "005"], coords: [0.3, 0.1], - nonFinite: Number.POSITIVE_INFINITY + nonFinite: Number.POSITIVE_INFINITY, }, { date: "2011-11-14T16:30:43Z", @@ -41,7 +41,7 @@ const someData = [ type: "tab", productIDs: ["001", "002"], coords: [0.392, 0.1], - nonFinite: Number.NEGATIVE_INFINITY + nonFinite: Number.NEGATIVE_INFINITY, }, { date: "2011-11-14T16:48:46Z", @@ -51,7 +51,7 @@ const someData = [ type: "tab", productIDs: ["005"], coords: [0.7, 0.0482], - nonFinite: 1.0 + nonFinite: 1.0, }, { date: "2011-11-14T16:53:41Z", @@ -61,7 +61,7 @@ const someData = [ type: "tab", productIDs: ["001", "004", "005"], coords: [0.9999, 1.0], - nonFinite: Number.NaN + nonFinite: Number.NaN, }, { date: "2011-11-14T16:54:06Z", @@ -71,7 +71,7 @@ const someData = [ type: "cash", productIDs: ["001", "002", "003", "004", "005"], coords: [0.384, 0.6938], - nonFinite: 99.0 + nonFinite: 99.0, }, { date: "2011-11-14T16:58:03Z", @@ -81,7 +81,7 @@ const someData = [ type: "tab", productIDs: ["001"], coords: [0.4822, 0.482], - nonFinite: Number.NaN + nonFinite: Number.NaN, }, { date: "2011-11-14T17:07:21Z", @@ -91,7 +91,7 @@ const someData = [ type: "tab", productIDs: ["004", "005"], coords: [0.2234, 0], - nonFinite: Number.NaN + nonFinite: Number.NaN, }, { date: "2011-11-14T17:22:59Z", @@ -101,7 +101,7 @@ const someData = [ type: "tab", productIDs: ["001", "002", "004", "005"], coords: [0.382, 0.38485], - nonFinite: -1 + nonFinite: -1, }, { date: "2011-11-14T17:25:45Z", @@ -111,7 +111,7 @@ const someData = [ type: "cash", productIDs: ["002"], coords: [0.998, 0.8472], - nonFinite: 0.0 + nonFinite: 0.0, }, { date: "2011-11-14T17:29:52Z", @@ -121,8 +121,8 @@ const someData = [ type: "visa", productIDs: ["004"], coords: [0.8273, 0.3384], - nonFinite: 0.0 - } + nonFinite: 0.0, + }, ]; let payments = null; @@ -248,16 +248,21 @@ describe("ImmutableTypedCrossfilter", () => { test("none", () => { expect(p.select("quantity", { mode: "none" }).countSelected()).toEqual(0); }); - test.each([[[]], [[2]], [[2, 1]], [[9, 82]], [[0, 1]]])("exact: %p", v => + test.each([[[]], [[2]], [[2, 1]], [[9, 82]], [[0, 1]]])("exact: %p", (v) => expect( p.select("quantity", { mode: "exact", values: v }).countSelected() - ).toEqual(_.filter(someData, d => v.includes(d.quantity)).length) + ).toEqual(_.filter(someData, (d) => v.includes(d.quantity)).length) ); - test.each([[0, 1], [1, 2], [0, 99], [99, 100000]])("range %p", (lo, hi) => + test.each([ + [0, 1], + [1, 2], + [0, 99], + [99, 100000], + ])("range %p", (lo, hi) => expect( p.select("quantity", { mode: "range", lo, hi }).countSelected() ).toEqual( - _.filter(someData, d => d.quantity >= lo && d.quantity < hi).length + _.filter(someData, (d) => d.quantity >= lo && d.quantity < hi).length ) ); test("bad mode", () => { @@ -284,11 +289,11 @@ describe("ImmutableTypedCrossfilter", () => { [["tab"]], [["visa"]], [["visa", "tab"]], - [["cash", "tab", "visa"]] - ])("exact: %p", v => + [["cash", "tab", "visa"]], + ])("exact: %p", (v) => expect( p.select("type", { mode: "exact", values: v }).countSelected() - ).toEqual(_.filter(someData, d => v.includes(d.type)).length) + ).toEqual(_.filter(someData, (d) => v.includes(d.type)).length) ); test("range", () => { expect(() => p.select("type", { mode: "range", lo: 0, hi: 9 })).toThrow( @@ -303,8 +308,8 @@ describe("ImmutableTypedCrossfilter", () => { describe("spatial dimension", () => { let p; beforeEach(() => { - const X = someData.map(r => r.coords[0]); - const Y = someData.map(r => r.coords[1]); + const X = someData.map((r) => r.coords[0]); + const Y = someData.map((r) => r.coords[1]); p = payments.addDimension("coords", "spatial", X, Y); }); @@ -316,34 +321,76 @@ describe("ImmutableTypedCrossfilter", () => { test("none", () => { expect(p.select("coords", { mode: "none" }).countSelected()).toEqual(0); }); - test.each([[0, 0, 1, 1], [0, 0, 0.5, 0.5], [0.5, 0.5, 1, 1]])( - "within-rect %d %d %d %d", - (minX, minY, maxX, maxY) => { - expect( - p - .select("coords", { mode: "within-rect", minX, minY, maxX, maxY }) - .allSelected() - ).toEqual( - _.filter(someData, d => { - const [x, y] = d.coords; - return minX <= x && x < maxX && minY <= y && y < maxY; - }) - ); - } - ); + test.each([ + [0, 0, 1, 1], + [0, 0, 0.5, 0.5], + [0.5, 0.5, 1, 1], + ])("within-rect %d %d %d %d", (minX, minY, maxX, maxY) => { + expect( + p + .select("coords", { mode: "within-rect", minX, minY, maxX, maxY }) + .allSelected() + ).toEqual( + _.filter(someData, (d) => { + const [x, y] = d.coords; + return minX <= x && x < maxX && minY <= y && y < maxY; + }) + ); + }); test.each([ [ - [[0, 0], [0, 1], [1, 1], [1, 0]], - [true, true, true, true, true, false, true, true, true, true, true, true] + [ + [0, 0], + [0, 1], + [1, 1], + [1, 0], + ], + [ + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + ], ], [ - [[0, 0], [0, 0.5], [0.5, 0.5], [0.5, 0]], - [true, true, true, true, false, false, false, true, true, true, false, false] - ] + [ + [0, 0], + [0, 0.5], + [0.5, 0.5], + [0.5, 0], + ], + [ + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + ], + ], ])("within-polygon %p", (polygon, expected) => { - expect(p.select("coords", { mode: "within-polygon", polygon }).allSelected()) - .toEqual(_.zip(someData, expected).filter(x => x[1]).map(x => x[0])); + expect( + p.select("coords", { mode: "within-polygon", polygon }).allSelected() + ).toEqual( + _.zip(someData, expected) + .filter((x) => x[1]) + .map((x) => x[0]) + ); }); }); @@ -381,7 +428,7 @@ describe("ImmutableTypedCrossfilter", () => { p .select("nonFinite", { mode: "exact", - values: [Number.POSITIVE_INFINITY] + values: [Number.POSITIVE_INFINITY], }) .countSelected() ).toEqual(1); @@ -389,7 +436,7 @@ describe("ImmutableTypedCrossfilter", () => { p .select("nonFinite", { mode: "exact", - values: [Number.NEGATIVE_INFINITY] + values: [Number.NEGATIVE_INFINITY], }) .countSelected() ).toEqual(1); @@ -402,7 +449,7 @@ describe("ImmutableTypedCrossfilter", () => { p .select("nonFinite", { mode: "exact", - values: [Number.POSITIVE_INFINITY, 0, 1, 99] + values: [Number.POSITIVE_INFINITY, 0, 1, 99], }) .countSelected() ).toEqual(6); @@ -414,7 +461,7 @@ describe("ImmutableTypedCrossfilter", () => { .select("nonFinite", { mode: "range", lo: 0, - hi: Number.POSITIVE_INFINITY + hi: Number.POSITIVE_INFINITY, }) .countSelected() ).toEqual(5); @@ -423,7 +470,7 @@ describe("ImmutableTypedCrossfilter", () => { .select("nonFinite", { mode: "range", lo: 0, - hi: Number.NaN + hi: Number.NaN, }) .countSelected() ).toEqual(6); @@ -432,7 +479,7 @@ describe("ImmutableTypedCrossfilter", () => { .select("nonFinite", { mode: "range", lo: Number.NEGATIVE_INFINITY, - hi: Number.POSITIVE_INFINITY + hi: Number.POSITIVE_INFINITY, }) .countSelected() ).toEqual(7); diff --git a/client/__tests__/util/typedCrossfilter/positiveInterval.test.js b/client/__tests__/util/typedCrossfilter/positiveInterval.test.js index 399ad9ec..1e9355fa 100644 --- a/client/__tests__/util/typedCrossfilter/positiveInterval.test.js +++ b/client/__tests__/util/typedCrossfilter/positiveInterval.test.js @@ -10,15 +10,30 @@ describe("canonicalize", () => { test("simple, already correct", () => { expect(PositiveIntervals.canonicalize([[0, 1]])).toEqual([[0, 1]]); - expect(PositiveIntervals.canonicalize([[0, 1], [2, 3]])).toEqual([ + expect( + PositiveIntervals.canonicalize([ + [0, 1], + [2, 3], + ]) + ).toEqual([ [0, 1], - [2, 3] + [2, 3], ]); }); test("non-canonical, need to be canonicalized", () => { - expect(PositiveIntervals.canonicalize([[0, 1], [1, 2]])).toEqual([[0, 2]]); - expect(PositiveIntervals.canonicalize([[1, 2], [2, 3]])).toEqual([[1, 3]]); + expect( + PositiveIntervals.canonicalize([ + [0, 1], + [1, 2], + ]) + ).toEqual([[0, 2]]); + expect( + PositiveIntervals.canonicalize([ + [1, 2], + [2, 3], + ]) + ).toEqual([[1, 3]]); }); }); @@ -26,14 +41,30 @@ describe("union", () => { test("empty range", () => { expect(PositiveIntervals.union([], [])).toEqual([]); expect(PositiveIntervals.union([], [[1, 2]])).toEqual([[1, 2]]); - expect(PositiveIntervals.union([], [[1, 2], [3, 4]])).toEqual([ + expect( + PositiveIntervals.union( + [], + [ + [1, 2], + [3, 4], + ] + ) + ).toEqual([ [1, 2], - [3, 4] + [3, 4], ]); expect(PositiveIntervals.union([[3, 4]], [])).toEqual([[3, 4]]); - expect(PositiveIntervals.union([[1, 2], [3, 4]], [])).toEqual([ + expect( + PositiveIntervals.union( + [ + [1, 2], + [3, 4], + ], + [] + ) + ).toEqual([ [1, 2], - [3, 4] + [3, 4], ]); expect(PositiveIntervals.union([[3, 3]], [])).toEqual([[3, 3]]); expect(PositiveIntervals.union([], [[3, 3]])).toEqual([[3, 3]]); @@ -44,17 +75,37 @@ describe("union", () => { expect(PositiveIntervals.union([[2, 3]], [[1, 2]])).toEqual([[1, 3]]); expect(PositiveIntervals.union([[1, 2]], [[3, 4]])).toEqual([ [1, 2], - [3, 4] + [3, 4], ]); expect( - PositiveIntervals.union([[1, 2], [3, 4]], [[6, 7], [19, 40]]) - ).toEqual([[1, 2], [3, 4], [6, 7], [19, 40]]); - expect(PositiveIntervals.union([[1, 4]], [[1, 1], [3, 4]])).toEqual([ - [1, 4] + PositiveIntervals.union( + [ + [1, 2], + [3, 4], + ], + [ + [6, 7], + [19, 40], + ] + ) + ).toEqual([ + [1, 2], + [3, 4], + [6, 7], + [19, 40], ]); + expect( + PositiveIntervals.union( + [[1, 4]], + [ + [1, 1], + [3, 4], + ] + ) + ).toEqual([[1, 4]]); expect(PositiveIntervals.union([[3, 3]], [[4, 4]])).toEqual([ [3, 3], - [4, 4] + [4, 4], ]); }); }); @@ -70,34 +121,43 @@ describe("intersection", () => { expect(PositiveIntervals.intersection([[1, 2]], [[2, 3]])).toEqual([]); expect(PositiveIntervals.intersection([[2, 3]], [[1, 2]])).toEqual([]); expect(PositiveIntervals.intersection([[1, 10]], [[1, 10]])).toEqual([ - [1, 10] + [1, 10], ]); expect(PositiveIntervals.intersection([[1, 10]], [[2, 8]])).toEqual([ - [2, 8] + [2, 8], ]); expect(PositiveIntervals.intersection([[2, 8]], [[1, 10]])).toEqual([ - [2, 8] + [2, 8], ]); expect(PositiveIntervals.intersection([[1, 10]], [[2, 12]])).toEqual([ - [2, 10] + [2, 10], ]); expect(PositiveIntervals.intersection([[2, 12]], [[1, 10]])).toEqual([ - [2, 10] + [2, 10], ]); expect(PositiveIntervals.intersection([[1, 10]], [[1, 8]])).toEqual([ - [1, 8] + [1, 8], ]); expect(PositiveIntervals.intersection([[1, 8]], [[1, 10]])).toEqual([ - [1, 8] + [1, 8], ]); - expect(PositiveIntervals.intersection([[1, 10]], [[1, 2], [6, 9]])).toEqual( - [[1, 2], [6, 9]] - ); - expect(PositiveIntervals.intersection([[0, 2638]], [[1363, 2638]])).toEqual( - [[1363, 2638]] - ); + expect( + PositiveIntervals.intersection( + [[1, 10]], + [ + [1, 2], + [6, 9], + ] + ) + ).toEqual([ + [1, 2], + [6, 9], + ]); + expect( + PositiveIntervals.intersection([[0, 2638]], [[1363, 2638]]) + ).toEqual([[1363, 2638]]); expect(PositiveIntervals.intersection([[1, 2]], [[1, 2]])).toEqual([ - [1, 2] + [1, 2], ]); }); }); @@ -110,32 +170,66 @@ describe("difference", () => { }); test("simple", () => { - expect(PositiveIntervals.difference([[1, 2], [3, 4]], [])).toEqual([ + expect( + PositiveIntervals.difference( + [ + [1, 2], + [3, 4], + ], + [] + ) + ).toEqual([ [1, 2], - [3, 4] - ]); - expect(PositiveIntervals.difference([[1, 2], [3, 10]], [[5, 10]])).toEqual([ - [1, 2], - [3, 5] - ]); - expect(PositiveIntervals.difference([[1, 2], [3, 10]], [[0, 5]])).toEqual([ - [5, 10] + [3, 4], ]); expect( - PositiveIntervals.difference([[0, 2638]], [[0, 1363], [2055, 2638]]) + PositiveIntervals.difference( + [ + [1, 2], + [3, 10], + ], + [[5, 10]] + ) + ).toEqual([ + [1, 2], + [3, 5], + ]); + expect( + PositiveIntervals.difference( + [ + [1, 2], + [3, 10], + ], + [[0, 5]] + ) + ).toEqual([[5, 10]]); + expect( + PositiveIntervals.difference( + [[0, 2638]], + [ + [0, 1363], + [2055, 2638], + ] + ) ).toEqual([[1363, 2055]]); expect( - PositiveIntervals.difference([[0, 1363], [2055, 2638]], [[0, 2638]]) + PositiveIntervals.difference( + [ + [0, 1363], + [2055, 2638], + ], + [[0, 2638]] + ) ).toEqual([]); expect(PositiveIntervals.difference([[0, 10]], [[0, 1]])).toEqual([ - [1, 10] + [1, 10], ]); expect(PositiveIntervals.difference([[0, 10]], [[1, 2]])).toEqual([ [0, 1], - [2, 10] + [2, 10], ]); expect(PositiveIntervals.difference([[0, 10]], [[9, 10]])).toEqual([ - [0, 9] + [0, 9], ]); }); }); diff --git a/client/__tests__/util/typedCrossfilter/sort.test.js b/client/__tests__/util/typedCrossfilter/sort.test.js index 2114c1b5..ea155c29 100644 --- a/client/__tests__/util/typedCrossfilter/sort.test.js +++ b/client/__tests__/util/typedCrossfilter/sort.test.js @@ -4,7 +4,7 @@ import { lowerBound, upperBound, lowerBoundIndirect, - upperBoundIndirect + upperBoundIndirect, } from "../../../src/util/typedCrossfilter/sort"; /* @@ -40,7 +40,7 @@ describe("sortArray", () => { ["a", "b", "0", "1"], [0, "a", true, null, undefined, 3.1415], fillRand(new Array(1000)), - ["a", NaN, null, pInf] + ["a", NaN, null, pInf], ].map((val, idx) => test(`JS vals ${idx}`, () => { expect(sortArray(val)).toMatchObject(val.sort()); @@ -49,7 +49,7 @@ describe("sortArray", () => { }); describe("finite numbers", () => { - [Array, Float32Array, Uint32Array, Int32Array, Float64Array].map(Type => + [Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) => test(Type.name, () => { expect(sortArray(Type.from([6, 5, 4, 3, 2, 1, 0]))).toMatchObject( Type.from([0, 1, 2, 3, 4, 5, 6]) @@ -131,7 +131,7 @@ describe("sortArray", () => { describe("sortIndex", () => { describe("finite numbers", () => { - [Array, Float32Array, Uint32Array, Int32Array, Float64Array].map(Type => + [Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) => test(Type.name, () => { const source1 = Type.from([6, 5, 4, 3, 2, 1, 0]); const index1 = fillRange(new Uint32Array(source1.length)); diff --git a/client/__tests__/util/typedCrossfilter/util.test.js b/client/__tests__/util/typedCrossfilter/util.test.js index 33b026d9..30f2212f 100644 --- a/client/__tests__/util/typedCrossfilter/util.test.js +++ b/client/__tests__/util/typedCrossfilter/util.test.js @@ -1,6 +1,6 @@ import { sliceByIndex, - makeSortIndex + makeSortIndex, } from "../../../src/util/typedCrossfilter/util"; import { rangeFill as fillRange } from "../../../src/util/range"; diff --git a/client/configuration/babel/babel.dev.js b/client/configuration/babel/babel.dev.js index 8309071b..8f32d635 100644 --- a/client/configuration/babel/babel.dev.js +++ b/client/configuration/babel/babel.dev.js @@ -3,7 +3,7 @@ module.exports = { cacheDirectory: true, presets: [ ["modern-browsers", { loose: true, modules: false }], - "@babel/preset-react" + "@babel/preset-react", ], plugins: [ "@babel/plugin-proposal-function-bind", @@ -11,6 +11,6 @@ module.exports = { ["@babel/plugin-proposal-class-properties", { loose: true }], "@babel/plugin-proposal-export-namespace-from", "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-proposal-nullish-coalescing-operator" - ] + "@babel/plugin-proposal-nullish-coalescing-operator", + ], }; diff --git a/client/configuration/babel/babel.prod.js b/client/configuration/babel/babel.prod.js index 45e09551..604e2ef2 100644 --- a/client/configuration/babel/babel.prod.js +++ b/client/configuration/babel/babel.prod.js @@ -2,7 +2,7 @@ module.exports = { babelrc: false, presets: [ ["modern-browsers", { loose: true, modules: false }], - "@babel/preset-react" + "@babel/preset-react", ], plugins: [ "@babel/plugin-proposal-function-bind", @@ -12,6 +12,6 @@ module.exports = { "@babel/plugin-transform-react-constant-elements", "@babel/plugin-transform-runtime", "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-proposal-nullish-coalescing-operator" - ] + "@babel/plugin-proposal-nullish-coalescing-operator", + ], }; diff --git a/client/configuration/eslint/eslint.js b/client/configuration/eslint/eslint.js index 9d2456fe..dd3c4a20 100644 --- a/client/configuration/eslint/eslint.js +++ b/client/configuration/eslint/eslint.js @@ -9,8 +9,8 @@ module.exports = { sourceType: "module", ecmaFeatures: { jsx: true, - generators: true - } + generators: true, + }, }, rules: { "no-magic-numbers": "off", @@ -26,7 +26,7 @@ module.exports = { "operator-linebreak": [ "error", "after", - { overrides: { "?": "before", ":": "before" } } + { overrides: { "?": "before", ":": "before" } }, ], "no-console": "off", "spaced-comment": ["error", "always", { exceptions: ["*"] }], @@ -35,13 +35,13 @@ module.exports = { "react/prop-types": [0], "space-before-function-paren": "off", "function-paren-newline": "off", - "prefer-destructuring": ["error", { object: true, array: false }] + "prefer-destructuring": ["error", { object: true, array: false }], }, overrides: [ { files: ["**/*.test.js"], env: { - jest: true // now **/*.test.js files' env has both es6 *and* jest + jest: true, // now **/*.test.js files' env has both es6 *and* jest }, // Can't extend in overrides: https://github.com/eslint/eslint/issues/8813 // "extends": ["plugin:jest/recommended"] @@ -51,8 +51,8 @@ module.exports = { "jest/no-focused-tests": "error", "jest/no-identical-title": "error", "jest/prefer-to-have-length": "warn", - "jest/valid-expect": "error" - } - } - ] + "jest/valid-expect": "error", + }, + }, + ], }; diff --git a/client/configuration/webpack/webpack.config.dev.js b/client/configuration/webpack/webpack.config.dev.js index 7191c812..5175a08b 100644 --- a/client/configuration/webpack/webpack.config.dev.js +++ b/client/configuration/webpack/webpack.config.dev.js @@ -18,7 +18,7 @@ module.exports = { path: path.resolve("build"), pathinfo: true, filename: "static/js/bundle.js", - publicPath: "/" + publicPath: "/", }, module: { rules: [ @@ -26,7 +26,7 @@ module.exports = { test: /\.js$/, include: src, loader: "babel-loader", - options: babelOptions + options: babelOptions, }, { test: /\.css$/, @@ -34,29 +34,29 @@ module.exports = { exclude: [path.resolve(src, "index.css")], loader: [ { - loader: "style-loader" + loader: "style-loader", }, { loader: "css-loader", options: { modules: { - localIdentName: "[name]__[local]___[hash:base64:5]" - } - } - } - ] + localIdentName: "[name]__[local]___[hash:base64:5]", + }, + }, + }, + ], }, { test: /index\.css$/, include: [path.resolve(src, "index.css")], loader: [ { - loader: "style-loader" + loader: "style-loader", }, { - loader: "css-loader" - } - ] + loader: "css-loader", + }, + ], }, { test: /\.json$/, include: [src, nodeModules], loader: "json-loader" }, @@ -64,14 +64,14 @@ module.exports = { test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|otf)$/i, loader: "file-loader", include: [nodeModules, fonts], - query: { name: "static/assets/[name].[ext]" } - } - ] + query: { name: "static/assets/[name].[ext]" }, + }, + ], }, plugins: [ new HtmlWebpackPlugin({ inject: true, - template: path.resolve("index.html") + template: path.resolve("index.html"), }), new FaviconsWebpackPlugin({ logo: "./favicon.png", @@ -84,16 +84,18 @@ module.exports = { coast: false, firefox: false, windows: false, - yandex: false - } - } + yandex: false, + }, + }, }), new webpack.NoEmitOnErrorsPlugin(), new webpack.DefinePlugin({ - __REACT_DEVTOOLS_GLOBAL_HOOK__: "({ isDisabled: true })" + __REACT_DEVTOOLS_GLOBAL_HOOK__: "({ isDisabled: true })", }), new webpack.DefinePlugin({ - "process.env.CXG_SERVER_PORT": JSON.stringify(process.env.CXG_SERVER_PORT) - }) - ] + "process.env.CXG_SERVER_PORT": JSON.stringify( + process.env.CXG_SERVER_PORT + ), + }), + ], }; diff --git a/client/index.html b/client/index.html index 134e38c9..be954386 100644 --- a/client/index.html +++ b/client/index.html @@ -1,12 +1,27 @@ - - + + cell×gene - +
- diff --git a/client/index_template.html b/client/index_template.html index 168b1d4b..83082374 100644 --- a/client/index_template.html +++ b/client/index_template.html @@ -1,60 +1,61 @@ - - - - cell×gene - - - - - + * { + box-sizing: border-box; + } + + + + + -
- {% for script in SCRIPTS %} - - {% endfor %} - {% for ils in INLINE_SCRIPTS %} - - {% endfor %} - +
+ {% for script in SCRIPTS %} + + {% endfor %} {% for ils in INLINE_SCRIPTS %} + + {% endfor %} + diff --git a/client/server/development.js b/client/server/development.js index 45de0162..c85b51ff 100644 --- a/client/server/development.js +++ b/client/server/development.js @@ -21,7 +21,7 @@ compiler.plugin("invalid", () => { console.log("Compiling..."); }); -compiler.plugin("done", stats => { +compiler.plugin("done", (stats) => { utils.formatStats(stats, CLIENT_PORT); }); @@ -33,7 +33,7 @@ app.use(historyApiFallback({ verbose: false })); app.use( require("webpack-dev-middleware")(compiler, { logLevel: "warn", - publicPath: config.output.publicPath + publicPath: config.output.publicPath, }) ); @@ -43,7 +43,7 @@ app.get("*", (req, res) => { res.sendFile(path.resolve("index.html")); }); -app.listen(CLIENT_PORT, err => { +app.listen(CLIENT_PORT, (err) => { if (err) { console.log(err); return; diff --git a/client/server/utils.js b/client/server/utils.js index f274b81c..7ec62ba4 100644 --- a/client/server/utils.js +++ b/client/server/utils.js @@ -36,10 +36,10 @@ var formatStats = (stats, port) => { var json = stats.toJson(); var formattedErrors = json.errors.map( - message => "Error in " + formatMessage(message) + (message) => "Error in " + formatMessage(message) ); var formattedWarnings = json.warnings.map( - message => "Warning in " + formatMessage(message) + (message) => "Warning in " + formatMessage(message) ); if (hasErrors) { @@ -48,7 +48,7 @@ var formatStats = (stats, port) => { if (formattedErrors.some(isLikelyASyntaxError)) { formattedErrors = formattedErrors.filter(isLikelyASyntaxError); } - formattedErrors.forEach(message => { + formattedErrors.forEach((message) => { console.log(message); console.log(); }); @@ -58,7 +58,7 @@ var formatStats = (stats, port) => { if (hasWarnings) { console.log(chalk.yellow("Compiled with warnings.")); console.log(); - formattedWarnings.forEach(message => { + formattedWarnings.forEach((message) => { console.log(message); console.log(); }); diff --git a/client/src/actions/index.js b/client/src/actions/index.js index b3aa4140..19ff498d 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -24,15 +24,17 @@ async function obsAnnotationFetchAndLoad(dispatch, schema) { const plimit = new PromiseLimit(5); return Promise.all( - columns.map(col => + columns.map((col) => plimit.add(() => - fetchBinary(`annotations/obs?annotation-name=${encodeURIComponent(col.name)}`) - .then(buffer => Universe.matrixFBSToDataframe(buffer)) - .then(df => + fetchBinary( + `annotations/obs?annotation-name=${encodeURIComponent(col.name)}` + ) + .then((buffer) => Universe.matrixFBSToDataframe(buffer)) + .then((df) => dispatch({ type: "universe: column load success", dim: "obsAnnotations", - dataframe: df + dataframe: df, }) ) ) @@ -48,14 +50,14 @@ async function varAnnotationFetchAndLoad(dispatch, schema) { const index = varAnnotations.index ?? false; const names = index ? [index] : []; return Promise.all( - names.map(name => + names.map((name) => fetchBinary(`annotations/var?annotation-name=${encodeURIComponent(name)}`) - .then(buffer => Universe.matrixFBSToDataframe(buffer)) - .then(df => + .then((buffer) => Universe.matrixFBSToDataframe(buffer)) + .then((df) => dispatch({ type: "universe: column load success", dim: "varAnnotations", - dataframe: df + dataframe: df, }) ) ) @@ -71,17 +73,18 @@ function layoutFetchAndLoad(dispatch, schema) { const plimit = new PromiseLimit(5); return Promise.all( - embNames.map(e => + embNames.map((e) => plimit.add(() => - fetchBinary(`layout/obs?layout-name=${encodeURIComponent(e)}`) - .then(buffer => Universe.matrixFBSToDataframe(buffer)) + fetchBinary( + `layout/obs?layout-name=${encodeURIComponent(e)}` + ).then((buffer) => Universe.matrixFBSToDataframe(buffer)) ) ) - ).then(dfs => + ).then((dfs) => dispatch({ type: "universe: column load success", dim: "obsLayout", - dataframe: Dataframe.Dataframe.empty().withColsFromAll(dfs) + dataframe: Dataframe.Dataframe.empty().withColsFromAll(dfs), }) ); } @@ -90,13 +93,12 @@ function layoutFetchAndLoad(dispatch, schema) { return promise fetching user-configured colors */ async function userColorsFetchAndLoad(dispatch) { - return fetchJson("colors") - .then(response => - dispatch({ - type: "universe: user color load success", - userColors: loadUserColorConfig(response) - }) - ); + return fetchJson("colors").then((response) => + dispatch({ + type: "universe: user color load success", + userColors: loadUserColorConfig(response), + }) + ); } /* @@ -185,11 +187,15 @@ async function _doRequestExpressionData(dispatch, getState, genes) { /* helper for this function only */ const fetchData = async (geneNames) => { const query = geneNames - .map(g => `var:${dubEncURIComponent(varIndexName)}=${dubEncURIComponent(g)}`) + .map( + (g) => + `var:${dubEncURIComponent(varIndexName)}=${dubEncURIComponent(g)}` + ) .join("&"); // TODO: why convert to an Object and not a Dataframe? - return fetchBinary(`data/var?${query}`) - .then(buffer => Universe.convertDataFBStoObject(universe, buffer)); + return fetchBinary(`data/var?${query}`).then((buffer) => + Universe.convertDataFBStoObject(universe, buffer) + ); }; /* preload data already in cache */ @@ -351,7 +357,7 @@ const requestDifferentialExpression = (set1, set2, num_genes = 10) => async ( */ const plimit = new PromiseLimit(5); await Promise.all( - topNGenes.map(gene => + topNGenes.map((gene) => plimit.add(() => _doRequestExpressionData(dispatch, getState, [gene])) ) ); @@ -432,11 +438,15 @@ const saveObsAnnotations = () => async (dispatch, getState) => { }; function fetchJson(pathAndQuery) { - return doJsonRequest(`${globals.API.prefix}${globals.API.version}${pathAndQuery}`); + return doJsonRequest( + `${globals.API.prefix}${globals.API.version}${pathAndQuery}` + ); } function fetchBinary(pathAndQuery) { - return doBinaryRequest(`${globals.API.prefix}${globals.API.version}${pathAndQuery}`); + return doBinaryRequest( + `${globals.API.prefix}${globals.API.version}${pathAndQuery}` + ); } export default { diff --git a/client/src/actions/reembed.js b/client/src/actions/reembed.js index 8e340816..f337d70d 100644 --- a/client/src/actions/reembed.js +++ b/client/src/actions/reembed.js @@ -3,7 +3,7 @@ import { Universe } from "../util/stateManager"; import { postNetworkErrorToast, postAsyncSuccessToast, - postAsyncFailureToast + postAsyncFailureToast, } from "../components/framework/toasters"; function abortableFetch(request, opts, timeout = 0) { @@ -18,7 +18,7 @@ function abortableFetch(request, opts, timeout = 0) { setTimeout(() => controller.abort(), timeout); } return fetch(request, { ...opts, signal }); - } + }, }; } @@ -38,19 +38,19 @@ async function doReembedFetch(dispatch, getState) { method: "PUT", headers: new Headers({ Accept: "application/octet-stream", - "Content-Type": "application/json" + "Content-Type": "application/json", }), body: JSON.stringify({ method: "umap", - filter: { obs: { index: cells } } + filter: { obs: { index: cells } }, }), - credentials: "include" + credentials: "include", }, 60000 // 1 minute timeout ); dispatch({ type: "reembed: request start", - abortableFetch: af + abortableFetch: af, }); const res = await af.ready(); @@ -82,17 +82,17 @@ export function requestReembed() { const buffer = await res.arrayBuffer(); const df = Universe.matrixFBSToDataframe(buffer); dispatch({ - type: "reembed: request completed" + type: "reembed: request completed", }); dispatch({ type: "reembed: add reembedding", embedding: df, - schema + schema, }); postAsyncSuccessToast("Re-embedding has completed."); } catch (error) { dispatch({ - type: "reembed: request aborted" + type: "reembed: request aborted", }); if (error.name === "AbortError") { postAsyncFailureToast("Re-embedding calculation was aborted."); @@ -108,6 +108,6 @@ export function reembedResetWorldToUniverse(dispatch, getState) { const { reembedController } = getState(); if (reembedController.pendingFetch) reembedController.pendingFetch.abort(); dispatch({ - type: "reembed: clear all reembeddings" + type: "reembed: clear all reembeddings", }); } diff --git a/client/src/components/app.js b/client/src/components/app.js index 59375e18..93e63b4f 100644 --- a/client/src/components/app.js +++ b/client/src/components/app.js @@ -14,10 +14,10 @@ import TermsOfServicePrompt from "./termsPrompt"; import actions from "../actions"; -@connect(state => ({ +@connect((state) => ({ loading: state.controls.loading, error: state.controls.error, - graphRenderCounter: state.controls.graphRenderCounter + graphRenderCounter: state.controls.graphRenderCounter, })) class App extends React.Component { constructor(props) { @@ -40,16 +40,16 @@ class App extends React.Component { type: "window resize", data: { height: window.innerHeight, - width: window.innerWidth - } + width: window.innerWidth, + }, }); }); dispatch({ type: "window resize", data: { height: window.innerHeight, - width: window.innerWidth - } + width: window.innerWidth, + }, }); } @@ -70,7 +70,7 @@ class App extends React.Component { position: "fixed", fontWeight: 500, top: window.innerHeight / 2, - left: window.innerWidth / 2 - 50 + left: window.innerWidth / 2 - 50, }} > loading cellxgene @@ -82,7 +82,7 @@ class App extends React.Component { position: "fixed", fontWeight: 500, top: window.innerHeight / 2, - left: window.innerWidth / 2 - 50 + left: window.innerWidth / 2 - 50, }} > error loading diff --git a/client/src/components/autosave/filenameDialog.js b/client/src/components/autosave/filenameDialog.js index 8550b9f5..e25792d1 100644 --- a/client/src/components/autosave/filenameDialog.js +++ b/client/src/components/autosave/filenameDialog.js @@ -7,10 +7,10 @@ import { InputGroup, Dialog, Classes, - Colors + Colors, } from "@blueprintjs/core"; -@connect(state => ({ +@connect((state) => ({ universe: state.universe, idhash: state.config?.parameters?.["annotations-user-data-idhash"] ?? null, annotations: state.annotations, @@ -18,13 +18,13 @@ 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) { super(props); this.state = { - filenameText: "" + filenameText: "", }; } @@ -36,7 +36,7 @@ class FilenameDialog extends React.Component { dispatch({ type: "set annotations collection name", - data: filenameText + data: filenameText, }); }; @@ -71,7 +71,7 @@ class FilenameDialog extends React.Component { fontStyle: "italic", fontSize: 12, marginTop: 5, - color: Colors.ORANGE3 + color: Colors.ORANGE3, }} > Name cannot be blank @@ -84,7 +84,7 @@ class FilenameDialog extends React.Component { fontStyle: "italic", fontSize: 12, marginTop: 5, - color: Colors.ORANGE3 + color: Colors.ORANGE3, }} > Only alphanumeric and underscore allowed @@ -108,7 +108,7 @@ class FilenameDialog extends React.Component { onClose={this.dismissFilenameDialog} >
{ + onSubmit={(e) => { e.preventDefault(); this.handleCreateFilename(); }} @@ -120,7 +120,9 @@ class FilenameDialog extends React.Component { autoFocus value={filenameText} intent={this.filenameError(filenameText) ? "warning" : "none"} - onChange={e => this.setState({ filenameText: e.target.value })} + onChange={(e) => + this.setState({ filenameText: e.target.value }) + } leftIcon="tag" />

{this.filenameErrorMessage(filenameText)} diff --git a/client/src/components/autosave/index.js b/client/src/components/autosave/index.js index 663e8bd1..cc37bf08 100644 --- a/client/src/components/autosave/index.js +++ b/client/src/components/autosave/index.js @@ -4,7 +4,7 @@ import * as globals from "../../globals"; import actions from "../../actions"; import FilenameDialog from "./filenameDialog"; -@connect(state => ({ +@connect((state) => ({ universe: state.universe, annotations: state.annotations, obsAnnotations: state.universe.obsAnnotations, @@ -12,13 +12,13 @@ import FilenameDialog from "./filenameDialog"; lastSavedObsAnnotations: state.autosave?.lastSavedObsAnnotations, error: state.autosave?.error, writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false, - initialDataLoadComplete: state.autosave?.initialDataLoadComplete + initialDataLoadComplete: state.autosave?.initialDataLoadComplete, })) class Autosave extends React.Component { constructor(props) { super(props); this.state = { - timer: null + timer: null, }; } @@ -64,22 +64,26 @@ class Autosave extends React.Component { } render() { - const { writableCategoriesEnabled, saveInProgress, initialDataLoadComplete } = this.props; + const { + writableCategoriesEnabled, + saveInProgress, + initialDataLoadComplete, + } = this.props; return writableCategoriesEnabled ? (

{this.statusMessage()} diff --git a/client/src/components/categorical/annoDialog.js b/client/src/components/categorical/annoDialog.js index 2ddfa935..8a169969 100644 --- a/client/src/components/categorical/annoDialog.js +++ b/client/src/components/categorical/annoDialog.js @@ -2,11 +2,11 @@ import React from "react"; import { connect } from "react-redux"; import { Button, Tooltip, Dialog, Classes, Colors } from "@blueprintjs/core"; -@connect(state => ({ +@connect((state) => ({ colorAccessor: state.colors.colorAccessor, categoricalSelection: state.categoricalSelection, annotations: state.annotations, - universe: state.universe + universe: state.universe, })) class AnnoDialog extends React.PureComponent { constructor(props) { @@ -30,13 +30,13 @@ class AnnoDialog extends React.PureComponent { primaryButtonText, secondaryButtonText, handleSecondaryButtonSubmit, - primaryButtonProps + primaryButtonProps, } = this.props; return ( { + onSubmit={(e) => { e.preventDefault(); }} > @@ -48,7 +48,7 @@ class AnnoDialog extends React.PureComponent { style={{ marginTop: 7, visibility: validationError ? "visible" : "hidden", - color: Colors.ORANGE3 + color: Colors.ORANGE3, }} > {errorMessage} diff --git a/client/src/components/categorical/annoSelect.js b/client/src/components/categorical/annoSelect.js index 5979747a..68257b0a 100644 --- a/client/src/components/categorical/annoSelect.js +++ b/client/src/components/categorical/annoSelect.js @@ -3,11 +3,11 @@ import { connect } from "react-redux"; import { Button, MenuItem } from "@blueprintjs/core"; import { Select } from "@blueprintjs/select"; -@connect(state => ({ +@connect((state) => ({ colorAccessor: state.colors.colorAccessor, categoricalSelection: state.categoricalSelection, annotations: state.annotations, - universe: state.universe + universe: state.universe, })) class DuplicateCategorySelect extends React.PureComponent { constructor(props) { @@ -19,7 +19,7 @@ class DuplicateCategorySelect extends React.PureComponent { const { allCategoryNames, categoryToDuplicate, - handleModalDuplicateCategorySelection + handleModalDuplicateCategorySelection, } = this.props; return (
@@ -37,7 +37,7 @@ class DuplicateCategorySelect extends React.PureComponent { return ; }} noResults={} - onItemSelect={d => { + onItemSelect={(d) => { handleModalDuplicateCategorySelection(d); }} > diff --git a/client/src/components/categorical/category/annoMenuCategory.js b/client/src/components/categorical/category/annoMenuCategory.js index b3771fc9..4df30db2 100644 --- a/client/src/components/categorical/category/annoMenuCategory.js +++ b/client/src/components/categorical/category/annoMenuCategory.js @@ -6,11 +6,11 @@ import { MenuItem, Popover, Position, - PopoverInteractionKind + PopoverInteractionKind, } from "@blueprintjs/core"; -@connect(state => ({ - annotations: state.annotations +@connect((state) => ({ + annotations: state.annotations, })) class AnnoMenuCategory extends React.PureComponent { constructor(props) { @@ -22,7 +22,7 @@ class AnnoMenuCategory extends React.PureComponent { const { dispatch, metadataField } = this.props; dispatch({ type: "annotation: activate add new label mode", - data: metadataField + data: metadataField, }); }; @@ -31,7 +31,7 @@ class AnnoMenuCategory extends React.PureComponent { dispatch({ type: "annotation: activate category edit mode", - data: metadataField + data: metadataField, }); }; @@ -39,7 +39,7 @@ class AnnoMenuCategory extends React.PureComponent { const { dispatch, metadataField } = this.props; dispatch({ type: "annotation: delete category", - metadataField + metadataField, }); }; @@ -50,7 +50,7 @@ class AnnoMenuCategory extends React.PureComponent { isUserAnno, createText, editText, - deleteText + deleteText, } = this.props; return ( diff --git a/client/src/components/categorical/labelInput.js b/client/src/components/categorical/labelInput.js index a183cf7e..cc929365 100644 --- a/client/src/components/categorical/labelInput.js +++ b/client/src/components/categorical/labelInput.js @@ -31,7 +31,7 @@ export default class LabelInput extends React.PureComponent { const queryResults = this.filterLabels(query); this.state = { query, - queryResults + queryResults, }; } @@ -42,7 +42,7 @@ export default class LabelInput extends React.PureComponent { const queryResults = this.filterLabels(query); this.setState({ query, - queryResults + queryResults, }); const { onChange } = this.props; @@ -57,7 +57,7 @@ export default class LabelInput extends React.PureComponent { if (target !== query && onSelect) onSelect(target, event); }; - handleKeyDown = e => { + handleKeyDown = (e) => { /* prevent these events from propagating to containing form/dialog and causing further side effects (eg, closing dialog, submitting @@ -72,7 +72,7 @@ export default class LabelInput extends React.PureComponent { } }; - handleChange = e => { + handleChange = (e) => { const { onChange } = this.props; if (onChange) onChange(e.target.value); }; @@ -112,16 +112,18 @@ export default class LabelInput extends React.PureComponent { /* empty query is wildcard */ if (query === "") { - return labelSuggestions.slice(0, LabelInput.QueryResultLimit).map(l => ({ - target: l, - score: -10000 - })); + return labelSuggestions + .slice(0, LabelInput.QueryResultLimit) + .map((l) => ({ + target: l, + score: -10000, + })); } /* else, do a fuzzy query */ const options = { limit: LabelInput.QueryResultLimit, - threshold: -10000 // don't return bad results + threshold: -10000, // don't return bad results }; let queryResults = fuzzysort.go(query, labelSuggestions, options); /* exact match will always be first in list */ @@ -149,18 +151,18 @@ export default class LabelInput extends React.PureComponent { const popoverProps = { minimal: true, - ...props.popoverProps + ...props.popoverProps, }; const inputProps = { ...props.inputProps, - autoFocus: false + autoFocus: false, }; const { queryResults } = this.state; return ( <> i.target} + inputValueRenderer={(i) => i.target} items={queryResults} itemRenderer={this.renderLabelSuggestion} onItemSelect={this.handleItemSelect} diff --git a/client/src/components/categorical/labelUtil.js b/client/src/components/categorical/labelUtil.js index c944b130..c550474a 100644 --- a/client/src/components/categorical/labelUtil.js +++ b/client/src/components/categorical/labelUtil.js @@ -4,60 +4,60 @@ import { Colors } from "@blueprintjs/core"; import { AnnotationsHelpers } from "../../util/stateManager"; export function isLabelErroneous(label, metadataField, ontology, schema) { - /* + /* return false if this is a LEGAL/acceptable category name or NULL/empty string, or return an error type. */ - /* allow empty string */ - if (label === "") return false; + /* allow empty string */ + if (label === "") return false; - /* check for label syntax errors, but allow terms in ontology */ - const termInOntology = ontology?.termSet.has(label) ?? false; - const error = AnnotationsHelpers.annotationNameIsErroneous(label); - if (error && !termInOntology) return error; + /* check for label syntax errors, but allow terms in ontology */ + const termInOntology = ontology?.termSet.has(label) ?? false; + const error = AnnotationsHelpers.annotationNameIsErroneous(label); + if (error && !termInOntology) return error; - /* disallow duplicates */ - const { obsByName } = schema.annotations; - if (obsByName[metadataField].categories.indexOf(label) !== -1) - return "duplicate"; + /* disallow duplicates */ + const { obsByName } = schema.annotations; + if (obsByName[metadataField].categories.indexOf(label) !== -1) + return "duplicate"; - /* otherwise, no error */ - return false; + /* otherwise, no error */ + return false; } /* all other errors - map code to human error message */ const errorMessageMap = { - "empty-string": "Blank names not allowed", - duplicate: "Name must be unique", - "trim-spaces": "Leading and trailing spaces not allowed", - "illegal-characters": - "Only alphanumeric and special characters (-_.) allowed", - "multi-space-run": "Multiple consecutive spaces not allowed" + "empty-string": "Blank names not allowed", + duplicate: "Name must be unique", + "trim-spaces": "Leading and trailing spaces not allowed", + "illegal-characters": + "Only alphanumeric and special characters (-_.) allowed", + "multi-space-run": "Multiple consecutive spaces not allowed", }; export function labelPrompt(err, prolog, epilog) { - let errPrompt = null; - if (err) { - let errMsg = errorMessageMap[err] ?? "error"; - errMsg = errMsg[0].toLowerCase() + errMsg.slice(1); - errPrompt = ( - - {errMsg} - - ); - } - return ( - - {prolog} - {err ? " - " : null} - {errPrompt} - {epilog} - - ); + let errPrompt = null; + if (err) { + let errMsg = errorMessageMap[err] ?? "error"; + errMsg = errMsg[0].toLowerCase() + errMsg.slice(1); + errPrompt = ( + + {errMsg} + + ); + } + return ( + + {prolog} + {err ? " - " : null} + {errPrompt} + {epilog} + + ); } diff --git a/client/src/components/continuous/setupParallelCoordinates.js b/client/src/components/continuous/setupParallelCoordinates.js index 90cb7f97..8f062143 100644 --- a/client/src/components/continuous/setupParallelCoordinates.js +++ b/client/src/components/continuous/setupParallelCoordinates.js @@ -33,7 +33,7 @@ const setupParallelCoordinates = (width, height, margin) => { return { svg, - ctx + ctx, }; }; diff --git a/client/src/components/continuous/util.js b/client/src/components/continuous/util.js index 8a156726..40462c6c 100644 --- a/client/src/components/continuous/util.js +++ b/client/src/components/continuous/util.js @@ -13,7 +13,7 @@ export const innerHeight = height - 2; export const devicePixelRatio = window.devicePixelRatio || 1; -export const createDimensions = data => { +export const createDimensions = (data) => { const newArr = []; _.each(data, (value, key) => { if (value.range) { @@ -21,12 +21,12 @@ export const createDimensions = data => { key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */, type: { within: (d, extent, dim) => - extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1] + extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1], }, scale: d3 .scaleSqrt() .range([innerHeight, 0]) - .domain([0, value.range.max]) + .domain([0, value.range.max]), }); } }); diff --git a/client/src/components/continuousLegend/index.js b/client/src/components/continuousLegend/index.js index db6b2d26..634f533c 100644 --- a/client/src/components/continuousLegend/index.js +++ b/client/src/components/continuousLegend/index.js @@ -38,12 +38,12 @@ const continuous = (selectorId, colorscale, colorAccessor) => { .range([1, legendheight - margin.top - margin.bottom]) .domain([ colorscale.domain()[1], - colorscale.domain()[0] + colorscale.domain()[0], ]); /* we flip this to make viridis colors dark if high in the color scale */ // image data hackery based on http://bl.ocks.org/mbostock/048d21cf747371b11884f75ad896e5a5 const image = ctx.createImageData(1, legendheight); - d3.range(legendheight).forEach(i => { + d3.range(legendheight).forEach((i) => { const c = d3.rgb(colorscale(legendscale.invert(i))); image.data[4 * i] = c.r; image.data[4 * i + 1] = c.g; @@ -62,11 +62,7 @@ const continuous = (selectorId, colorscale, colorAccessor) => { }); */ - const legendaxis = d3 - .axisRight() - .scale(legendscale) - .tickSize(6) - .ticks(8); + const legendaxis = d3.axisRight().scale(legendscale).tickSize(6).ticks(8); const svg = d3 .select(selectorId) @@ -98,10 +94,10 @@ const continuous = (selectorId, colorscale, colorAccessor) => { .text(colorAccessor); }; -@connect(state => ({ +@connect((state) => ({ colorAccessor: state.colors.colorAccessor, colorScale: state.colors.scale, - responsive: state.responsive + responsive: state.responsive, })) class ContinuousLegend extends React.Component { constructor(props) { @@ -118,9 +114,7 @@ class ContinuousLegend extends React.Component { prevProps.responsive.width !== responsive.width ) { /* always remove it, if it's not continuous we don't put it back. */ - d3.select("#continuous_legend") - .selectAll("*") - .remove(); + d3.select("#continuous_legend").selectAll("*").remove(); } if (colorAccessor && colorScale && colorScale.range) { @@ -144,7 +138,7 @@ class ContinuousLegend extends React.Component { position: "fixed", display: colorAccessor ? "inherit" : "none", right: globals.leftSidebarWidth, - top: responsive.height / 2 + top: responsive.height / 2, }} /> ); diff --git a/client/src/components/framework/container.js b/client/src/components/framework/container.js index ce738d19..558df99f 100644 --- a/client/src/components/framework/container.js +++ b/client/src/components/framework/container.js @@ -3,7 +3,7 @@ import React from "react"; import styles from "./container.css"; -const Container = props => { +const Container = (props) => { const { children } = props; return
{children}
; }; diff --git a/client/src/components/framework/logo.js b/client/src/components/framework/logo.js index 6d378e11..e95e4b1c 100644 --- a/client/src/components/framework/logo.js +++ b/client/src/components/framework/logo.js @@ -1,7 +1,7 @@ import React from "react"; import * as globals from "../../globals"; -const Logo = props => { +const Logo = (props) => { const { size } = props; return ( diff --git a/client/src/components/geneExpression/index.js b/client/src/components/geneExpression/index.js index 4a9448bf..a088ca8e 100644 --- a/client/src/components/geneExpression/index.js +++ b/client/src/components/geneExpression/index.js @@ -11,7 +11,7 @@ import { Button, FormGroup, InputGroup, - ControlGroup + ControlGroup, } from "@blueprintjs/core"; import { Suggest } from "@blueprintjs/select"; import HistogramBrush from "../brushableHistogram"; @@ -19,7 +19,7 @@ import * as globals from "../../globals"; import actions from "../../actions"; import { postUserErrorToast, - keepAroundErrorToast + keepAroundErrorToast, } from "../framework/toasters"; import { memoize } from "../../util/dataframe/util"; @@ -40,7 +40,7 @@ const renderGene = (fuzzySortResult, { handleClick, modifiers }) => { // See https://github.com/chanzuckerberg/cellxgene/issues/483 // label={gene.n_counts} key={geneName} - onClick={g => + onClick={(g) => /* this fires when user clicks a menu item */ handleClick(g) } @@ -53,17 +53,17 @@ const filterGenes = (query, genes) => /* fires on load, once, and then for each character typed into the input */ fuzzysort.go(query, genes, { limit: 5, - threshold: -10000 // don't return bad results + threshold: -10000, // don't return bad results }); -@connect(state => { +@connect((state) => { return { obsAnnotations: state.world?.obsAnnotations, userDefinedGenes: state.controls.userDefinedGenes, userDefinedGenesLoading: state.controls.userDefinedGenesLoading, world: state.world, colorAccessor: state.colors.colorAccessor, - differential: state.differential + differential: state.differential, }; }) class GeneExpression extends React.Component { @@ -72,11 +72,11 @@ class GeneExpression extends React.Component { this.state = { bulkAdd: "", tab: "autosuggest", - activeItem: null + activeItem: null, }; } - _genesToUpper = listGenes => { + _genesToUpper = (listGenes) => { // Has to be a Map to preserve index const upperGenes = new Map(); for (let i = 0, { length } = listGenes; i < length; i += 1) { @@ -87,7 +87,7 @@ class GeneExpression extends React.Component { }; // eslint-disable-next-line react/sort-comp - _memoGenesToUpper = memoize(this._genesToUpper, arr => arr); + _memoGenesToUpper = memoize(this._genesToUpper, (arr) => arr); handleBulkAddClick = () => { const { world, dispatch, userDefinedGenes } = this.props; @@ -115,7 +115,7 @@ class GeneExpression extends React.Component { dispatch({ type: "bulk user defined gene start" }); Promise.all( - [...upperGenes.keys()].map(upperGene => { + [...upperGenes.keys()].map((upperGene) => { if (upperUserDefinedGenes.get(upperGene) !== undefined) { return keepAroundErrorToast("That gene already exists"); } @@ -204,7 +204,7 @@ class GeneExpression extends React.Component { world, userDefinedGenes, userDefinedGenesLoading, - differential + differential, } = this.props; const varIndexName = world?.schema?.annotations?.var?.index; const varIndex = world?.varAnnotations?.col(varIndexName)?.asArray(); @@ -218,7 +218,7 @@ class GeneExpression extends React.Component {