mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-09 04:48:12 +08:00
* Added TS. Updated build and linting config. Added types. * [ts-migrate][.] Rename files from JS/JSX to TS/TSX Co-authored-by: ts-migrate <> * [ts-migrate][.] Run TS Migrate Co-authored-by: ts-migrate <> * Corrected files mangled by ts-migrate. * Updated lint config, minor linting. * Re-enabled Husky. * Updated tests and config. * Reverted webpack devtool config. * Removed obsolete snapshots. * Added annotations snap. * Updated tsconfig includes wrt linting. * Removed ts-migrate. Co-authored-by: Timmy Huang <tihuan@users.noreply.github.com>
This commit is contained in:
co-authored by
ts-migrate
Timmy Huang
parent
7328cbdbd5
commit
934cc5c69b
+76
-42
@@ -18,12 +18,17 @@ import {
|
|||||||
|
|
||||||
import { appUrlBase, TEST_EMAIL, TEST_PASSWORD } from "./config";
|
import { appUrlBase, TEST_EMAIL, TEST_PASSWORD } from "./config";
|
||||||
|
|
||||||
export async function drag(testId, start, end, lasso = false) {
|
export async function drag(testId: any, start: any, end: any, lasso = false) {
|
||||||
const layout = await waitByID(testId);
|
const layout = await waitByID(testId);
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const elBox = await layout.boxModel();
|
const elBox = await layout.boxModel();
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const x1 = elBox.content[0].x + start.x;
|
const x1 = elBox.content[0].x + start.x;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const x2 = elBox.content[0].x + end.x;
|
const x2 = elBox.content[0].x + end.x;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const y1 = elBox.content[0].y + start.y;
|
const y1 = elBox.content[0].y + start.y;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const y2 = elBox.content[0].y + end.y;
|
const y2 = elBox.content[0].y + end.y;
|
||||||
await page.mouse.move(x1, y1);
|
await page.mouse.move(x1, y1);
|
||||||
await page.mouse.down();
|
await page.mouse.down();
|
||||||
@@ -38,7 +43,7 @@ export async function drag(testId, start, end, lasso = false) {
|
|||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickOnCoordinate(testId, coord) {
|
export async function clickOnCoordinate(testId: any, coord: any) {
|
||||||
const layout = await expect(page).toMatchElement(getTestId(testId));
|
const layout = await expect(page).toMatchElement(getTestId(testId));
|
||||||
const elBox = await layout.boxModel();
|
const elBox = await layout.boxModel();
|
||||||
|
|
||||||
@@ -51,11 +56,12 @@ export async function clickOnCoordinate(testId, coord) {
|
|||||||
await page.mouse.click(x, y);
|
await page.mouse.click(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllHistograms(testclass, testIds) {
|
export async function getAllHistograms(testclass: any, testIds: any) {
|
||||||
const histTestIds = testIds.map((tid) => `histogram-${tid}`);
|
const histTestIds = testIds.map((tid: any) => `histogram-${tid}`);
|
||||||
|
|
||||||
// these load asynchronously, so we need to wait for each histogram individually,
|
// these load asynchronously, so we need to wait for each histogram individually,
|
||||||
// and they may be quite slow in some cases.
|
// and they may be quite slow in some cases.
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 2.
|
||||||
await waitForAllByIds(histTestIds, { timeout: 4 * 60 * 1000 });
|
await waitForAllByIds(histTestIds, { timeout: 4 * 60 * 1000 });
|
||||||
|
|
||||||
const allHistograms = await getAllByClass(testclass);
|
const allHistograms = await getAllByClass(testclass);
|
||||||
@@ -71,7 +77,7 @@ export async function getAllHistograms(testclass, testIds) {
|
|||||||
return testIDs.map((id) => id.replace(/^histogram-/, ""));
|
return testIDs.map((id) => id.replace(/^histogram-/, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllCategoriesAndCounts(category) {
|
export async function getAllCategoriesAndCounts(category: any) {
|
||||||
// these load asynchronously, so we have to wait for the specific category.
|
// these load asynchronously, so we have to wait for the specific category.
|
||||||
await waitByID(`category-${category}`);
|
await waitByID(`category-${category}`);
|
||||||
|
|
||||||
@@ -80,13 +86,14 @@ export async function getAllCategoriesAndCounts(category) {
|
|||||||
(rows) =>
|
(rows) =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
rows.map((row) => {
|
rows.map((row) => {
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const cat = row
|
const cat = row
|
||||||
.querySelector("[data-testclass='categorical-value']")
|
.querySelector("[data-testclass='categorical-value']")
|
||||||
.getAttribute("aria-label");
|
.getAttribute("aria-label");
|
||||||
|
|
||||||
const count = row.querySelector(
|
const count = (row.querySelector(
|
||||||
"[data-testclass='categorical-value-count']"
|
"[data-testclass='categorical-value-count']"
|
||||||
).innerText;
|
) as any).innerText;
|
||||||
|
|
||||||
return [cat, count];
|
return [cat, count];
|
||||||
})
|
})
|
||||||
@@ -94,12 +101,12 @@ export async function getAllCategoriesAndCounts(category) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCellSetCount(num) {
|
export async function getCellSetCount(num: any) {
|
||||||
await clickOn(`cellset-button-${num}`);
|
await clickOn(`cellset-button-${num}`);
|
||||||
return getOneElementInnerText(`[data-testid='cellset-count-${num}']`);
|
return getOneElementInnerText(`[data-testid='cellset-count-${num}']`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resetCategory(category) {
|
export async function resetCategory(category: any) {
|
||||||
const checkboxId = `${category}:category-select`;
|
const checkboxId = `${category}:category-select`;
|
||||||
await waitByID(checkboxId);
|
await waitByID(checkboxId);
|
||||||
const checkedPseudoclass = await page.$eval(
|
const checkedPseudoclass = await page.$eval(
|
||||||
@@ -110,6 +117,7 @@ export async function resetCategory(category) {
|
|||||||
|
|
||||||
const categoryRow = await waitByID(`${category}:category-expand`);
|
const categoryRow = await waitByID(`${category}:category-expand`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const isExpanded = await categoryRow.$(
|
const isExpanded = await categoryRow.$(
|
||||||
"[data-testclass='category-expand-is-expanded']"
|
"[data-testclass='category-expand-is-expanded']"
|
||||||
);
|
);
|
||||||
@@ -117,16 +125,26 @@ export async function resetCategory(category) {
|
|||||||
if (isExpanded) await clickOn(`${category}:category-expand`);
|
if (isExpanded) await clickOn(`${category}:category-expand`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function calcCoordinate(testId, xAsPercent, yAsPercent) {
|
export async function calcCoordinate(
|
||||||
|
testId: any,
|
||||||
|
xAsPercent: any,
|
||||||
|
yAsPercent: any
|
||||||
|
) {
|
||||||
const el = await waitByID(testId);
|
const el = await waitByID(testId);
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const size = await el.boxModel();
|
const size = await el.boxModel();
|
||||||
return {
|
return {
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
x: Math.floor(size.width * xAsPercent),
|
x: Math.floor(size.width * xAsPercent),
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
y: Math.floor(size.height * yAsPercent),
|
y: Math.floor(size.height * yAsPercent),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function calcDragCoordinates(testId, coordinateAsPercent) {
|
export async function calcDragCoordinates(
|
||||||
|
testId: any,
|
||||||
|
coordinateAsPercent: any
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
start: await calcCoordinate(
|
start: await calcCoordinate(
|
||||||
testId,
|
testId,
|
||||||
@@ -141,7 +159,7 @@ export async function calcDragCoordinates(testId, coordinateAsPercent) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function selectCategory(category, values, reset = true) {
|
export async function selectCategory(category: any, values: any, reset = true) {
|
||||||
if (reset) await resetCategory(category);
|
if (reset) await resetCategory(category);
|
||||||
|
|
||||||
await clickOn(`${category}:category-expand`);
|
await clickOn(`${category}:category-expand`);
|
||||||
@@ -152,8 +170,9 @@ export async function selectCategory(category, values, reset = true) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function expandCategory(category) {
|
export async function expandCategory(category: any) {
|
||||||
const expand = await waitByID(`${category}:category-expand`);
|
const expand = await waitByID(`${category}:category-expand`);
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const notExpanded = await expand.$(
|
const notExpanded = await expand.$(
|
||||||
"[data-testclass='category-expand-is-not-expanded']"
|
"[data-testclass='category-expand-is-not-expanded']"
|
||||||
);
|
);
|
||||||
@@ -167,7 +186,7 @@ export async function clip(min = 0, max = 100) {
|
|||||||
await clickOn("clip-commit");
|
await clickOn("clip-commit");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCategory(categoryName) {
|
export async function createCategory(categoryName: any) {
|
||||||
await clickOnUntil("open-annotation-dialog", async () => {
|
await clickOnUntil("open-annotation-dialog", async () => {
|
||||||
await expect(page).toMatchElement(getTestId("new-category-name"));
|
await expect(page).toMatchElement(getTestId("new-category-name"));
|
||||||
});
|
});
|
||||||
@@ -182,17 +201,18 @@ export async function createCategory(categoryName) {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function colorByGeneset(genesetName) {
|
export async function colorByGeneset(genesetName: any) {
|
||||||
await clickOn(`${genesetName}:colorby-entire-geneset`);
|
await clickOn(`${genesetName}:colorby-entire-geneset`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function colorByGene(gene) {
|
export async function colorByGene(gene: any) {
|
||||||
await clickOn(`colorby-${gene}`);
|
await clickOn(`colorby-${gene}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertColorLegendLabel(label) {
|
export async function assertColorLegendLabel(label: any) {
|
||||||
const handle = await waitByID("continuous_legend_color_by_label");
|
const handle = await waitByID("continuous_legend_color_by_label");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const result = await handle.evaluate((node) => {
|
const result = await handle.evaluate((node) => {
|
||||||
return node.getAttribute("aria-label");
|
return node.getAttribute("aria-label");
|
||||||
});
|
});
|
||||||
@@ -200,15 +220,16 @@ export async function assertColorLegendLabel(label) {
|
|||||||
return expect(result).toBe(label);
|
return expect(result).toBe(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function expandGeneset(genesetName) {
|
export async function expandGeneset(genesetName: any) {
|
||||||
const expand = await waitByID(`${genesetName}:geneset-expand`);
|
const expand = await waitByID(`${genesetName}:geneset-expand`);
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const notExpanded = await expand.$(
|
const notExpanded = await expand.$(
|
||||||
"[data-testclass='geneset-expand-is-not-expanded']"
|
"[data-testclass='geneset-expand-is-not-expanded']"
|
||||||
);
|
);
|
||||||
if (notExpanded) await clickOn(`${genesetName}:geneset-expand`);
|
if (notExpanded) await clickOn(`${genesetName}:geneset-expand`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createGeneset(genesetName) {
|
export async function createGeneset(genesetName: any) {
|
||||||
await clickOnUntil("open-create-geneset-dialog", async () => {
|
await clickOnUntil("open-create-geneset-dialog", async () => {
|
||||||
await expect(page).toMatchElement(getTestId("create-geneset-input"));
|
await expect(page).toMatchElement(getTestId("create-geneset-input"));
|
||||||
});
|
});
|
||||||
@@ -218,7 +239,7 @@ export async function createGeneset(genesetName) {
|
|||||||
await waitByClass("autosave-complete");
|
await waitByClass("autosave-complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function editGenesetName(genesetName, editText) {
|
export async function editGenesetName(genesetName: any, editText: any) {
|
||||||
const editButton = `${genesetName}:edit-genesetName-mode`;
|
const editButton = `${genesetName}:edit-genesetName-mode`;
|
||||||
const submitButton = `${genesetName}:submit-geneset`;
|
const submitButton = `${genesetName}:submit-geneset`;
|
||||||
await clickOnUntil(`${genesetName}:see-actions`, async () => {
|
await clickOnUntil(`${genesetName}:see-actions`, async () => {
|
||||||
@@ -229,7 +250,7 @@ export async function editGenesetName(genesetName, editText) {
|
|||||||
await clickOn(submitButton);
|
await clickOn(submitButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteGeneset(genesetName) {
|
export async function deleteGeneset(genesetName: any) {
|
||||||
const targetId = `${genesetName}:delete-geneset`;
|
const targetId = `${genesetName}:delete-geneset`;
|
||||||
|
|
||||||
await clickOnUntil(`${genesetName}:see-actions`, async () => {
|
await clickOnUntil(`${genesetName}:see-actions`, async () => {
|
||||||
@@ -242,16 +263,18 @@ export async function deleteGeneset(genesetName) {
|
|||||||
await waitByClass("autosave-complete");
|
await waitByClass("autosave-complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertGenesetDoesNotExist(genesetName) {
|
export async function assertGenesetDoesNotExist(genesetName: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const result = await isElementPresent(
|
const result = await isElementPresent(
|
||||||
getTestId(`${genesetName}:geneset-name`)
|
getTestId(`${genesetName}:geneset-name`)
|
||||||
);
|
);
|
||||||
await expect(result).toBe(false);
|
await expect(result).toBe(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertGenesetExists(genesetName) {
|
export async function assertGenesetExists(genesetName: any) {
|
||||||
const handle = await waitByID(`${genesetName}:geneset-name`);
|
const handle = await waitByID(`${genesetName}:geneset-name`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const result = await handle.evaluate((node) => {
|
const result = await handle.evaluate((node) => {
|
||||||
return node.getAttribute("aria-label");
|
return node.getAttribute("aria-label");
|
||||||
});
|
});
|
||||||
@@ -265,7 +288,7 @@ export async function assertGenesetExists(genesetName) {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function addGeneToSet(genesetName, geneToAddToSet) {
|
export async function addGeneToSet(genesetName: any, geneToAddToSet: any) {
|
||||||
const submitButton = `${genesetName}:submit-gene`;
|
const submitButton = `${genesetName}:submit-gene`;
|
||||||
|
|
||||||
await clickOn(`${genesetName}:add-new-gene-to-geneset`);
|
await clickOn(`${genesetName}:add-new-gene-to-geneset`);
|
||||||
@@ -273,7 +296,7 @@ export async function addGeneToSet(genesetName, geneToAddToSet) {
|
|||||||
await clickOn(submitButton);
|
await clickOn(submitButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeGene(geneSymbol) {
|
export async function removeGene(geneSymbol: any) {
|
||||||
const targetId = `delete-from-geneset:${geneSymbol}`;
|
const targetId = `delete-from-geneset:${geneSymbol}`;
|
||||||
|
|
||||||
await clickOn(targetId);
|
await clickOn(targetId);
|
||||||
@@ -281,9 +304,10 @@ export async function removeGene(geneSymbol) {
|
|||||||
await waitByClass("autosave-complete");
|
await waitByClass("autosave-complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertGeneExistsInGeneset(geneSymbol) {
|
export async function assertGeneExistsInGeneset(geneSymbol: any) {
|
||||||
const handle = await waitByID(`${geneSymbol}:gene-label`);
|
const handle = await waitByID(`${geneSymbol}:gene-label`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const result = await handle.evaluate((node) => {
|
const result = await handle.evaluate((node) => {
|
||||||
return node.getAttribute("aria-label");
|
return node.getAttribute("aria-label");
|
||||||
});
|
});
|
||||||
@@ -291,13 +315,14 @@ export async function assertGeneExistsInGeneset(geneSymbol) {
|
|||||||
return expect(result).toBe(geneSymbol);
|
return expect(result).toBe(geneSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertGeneDoesNotExist(geneSymbol) {
|
export async function assertGeneDoesNotExist(geneSymbol: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const result = await isElementPresent(getTestId(`${geneSymbol}:gene-label`));
|
const result = await isElementPresent(getTestId(`${geneSymbol}:gene-label`));
|
||||||
|
|
||||||
await expect(result).toBe(false);
|
await expect(result).toBe(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function expandGene(geneSymbol) {
|
export async function expandGene(geneSymbol: any) {
|
||||||
await clickOn(`maximize-${geneSymbol}`);
|
await clickOn(`maximize-${geneSymbol}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +332,7 @@ export async function expandGene(geneSymbol) {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function duplicateCategory(categoryName) {
|
export async function duplicateCategory(categoryName: any) {
|
||||||
await clickOn("open-annotation-dialog");
|
await clickOn("open-annotation-dialog");
|
||||||
|
|
||||||
await typeInto("new-category-name", categoryName);
|
await typeInto("new-category-name", categoryName);
|
||||||
@@ -333,7 +358,10 @@ export async function duplicateCategory(categoryName) {
|
|||||||
await waitByClass("autosave-complete");
|
await waitByClass("autosave-complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renameCategory(oldCategoryName, newCategoryName) {
|
export async function renameCategory(
|
||||||
|
oldCategoryName: any,
|
||||||
|
newCategoryName: any
|
||||||
|
) {
|
||||||
await clickOn(`${oldCategoryName}:see-actions`);
|
await clickOn(`${oldCategoryName}:see-actions`);
|
||||||
await clickOn(`${oldCategoryName}:edit-category-mode`);
|
await clickOn(`${oldCategoryName}:edit-category-mode`);
|
||||||
await clearInputAndTypeInto(
|
await clearInputAndTypeInto(
|
||||||
@@ -343,7 +371,7 @@ export async function renameCategory(oldCategoryName, newCategoryName) {
|
|||||||
await clickOn(`${oldCategoryName}:submit-category-edit`);
|
await clickOn(`${oldCategoryName}:submit-category-edit`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteCategory(categoryName) {
|
export async function deleteCategory(categoryName: any) {
|
||||||
const targetId = `${categoryName}:delete-category`;
|
const targetId = `${categoryName}:delete-category`;
|
||||||
|
|
||||||
await clickOnUntil(`${categoryName}:see-actions`, async () => {
|
await clickOnUntil(`${categoryName}:see-actions`, async () => {
|
||||||
@@ -352,10 +380,11 @@ export async function deleteCategory(categoryName) {
|
|||||||
|
|
||||||
await clickOn(targetId);
|
await clickOn(targetId);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
await assertCategoryDoesNotExist();
|
await assertCategoryDoesNotExist();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createLabel(categoryName, labelName) {
|
export async function createLabel(categoryName: any, labelName: any) {
|
||||||
/**
|
/**
|
||||||
* (thuang): This explicit wait is needed, since currently showing
|
* (thuang): This explicit wait is needed, since currently showing
|
||||||
* the modal again quickly after the previous action dismissing the
|
* the modal again quickly after the previous action dismissing the
|
||||||
@@ -380,13 +409,17 @@ export async function createLabel(categoryName, labelName) {
|
|||||||
await clickOn(`${categoryName}:submit-label`);
|
await clickOn(`${categoryName}:submit-label`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteLabel(categoryName, labelName) {
|
export async function deleteLabel(categoryName: any, labelName: any) {
|
||||||
await expandCategory(categoryName);
|
await expandCategory(categoryName);
|
||||||
await clickOn(`${categoryName}:${labelName}:see-actions`);
|
await clickOn(`${categoryName}:${labelName}:see-actions`);
|
||||||
await clickOn(`${categoryName}:${labelName}:delete-label`);
|
await clickOn(`${categoryName}:${labelName}:delete-label`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renameLabel(categoryName, oldLabelName, newLabelName) {
|
export async function renameLabel(
|
||||||
|
categoryName: any,
|
||||||
|
oldLabelName: any,
|
||||||
|
newLabelName: any
|
||||||
|
) {
|
||||||
await expandCategory(categoryName);
|
await expandCategory(categoryName);
|
||||||
await clickOn(`${categoryName}:${oldLabelName}:see-actions`);
|
await clickOn(`${categoryName}:${oldLabelName}:see-actions`);
|
||||||
await clickOn(`${categoryName}:${oldLabelName}:edit-label`);
|
await clickOn(`${categoryName}:${oldLabelName}:edit-label`);
|
||||||
@@ -397,13 +430,13 @@ export async function renameLabel(categoryName, oldLabelName, newLabelName) {
|
|||||||
await clickOn(`${categoryName}:${oldLabelName}:submit-label-edit`);
|
await clickOn(`${categoryName}:${oldLabelName}:submit-label-edit`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addGeneToSearch(geneName) {
|
export async function addGeneToSearch(geneName: any) {
|
||||||
await typeInto("gene-search", geneName);
|
await typeInto("gene-search", geneName);
|
||||||
await page.keyboard.press("Enter");
|
await page.keyboard.press("Enter");
|
||||||
await page.waitForSelector(`[data-testid='histogram-${geneName}']`);
|
await page.waitForSelector(`[data-testid='histogram-${geneName}']`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function subset(coordinatesAsPercent) {
|
export async function subset(coordinatesAsPercent: any) {
|
||||||
// In order to deselect the selection after the subset, make sure we have some clear part
|
// In order to deselect the selection after the subset, make sure we have some clear part
|
||||||
// of the scatterplot we can click on
|
// of the scatterplot we can click on
|
||||||
assert(coordinatesAsPercent.x2 < 0.99 || coordinatesAsPercent.y2 < 0.99);
|
assert(coordinatesAsPercent.x2 < 0.99 || coordinatesAsPercent.y2 < 0.99);
|
||||||
@@ -417,8 +450,8 @@ export async function subset(coordinatesAsPercent) {
|
|||||||
await clickOnCoordinate("layout-graph", clearCoordinate);
|
await clickOnCoordinate("layout-graph", clearCoordinate);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setSellSet(cellSet, cellSetNum) {
|
export async function setSellSet(cellSet: any, cellSetNum: any) {
|
||||||
const selections = cellSet.filter((sel) => sel.kind === "categorical");
|
const selections = cellSet.filter((sel: any) => sel.kind === "categorical");
|
||||||
|
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
await selectCategory(selection.metadata, selection.values, true);
|
await selectCategory(selection.metadata, selection.values, true);
|
||||||
@@ -427,19 +460,20 @@ export async function setSellSet(cellSet, cellSetNum) {
|
|||||||
await getCellSetCount(cellSetNum);
|
await getCellSetCount(cellSetNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runDiffExp(cellSet1, cellSet2) {
|
export async function runDiffExp(cellSet1: any, cellSet2: any) {
|
||||||
await setSellSet(cellSet1, 1);
|
await setSellSet(cellSet1, 1);
|
||||||
await setSellSet(cellSet2, 2);
|
await setSellSet(cellSet2, 2);
|
||||||
await clickOn("diffexp-button");
|
await clickOn("diffexp-button");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function bulkAddGenes(geneNames) {
|
export async function bulkAddGenes(geneNames: any) {
|
||||||
await clickOn("section-bulk-add");
|
await clickOn("section-bulk-add");
|
||||||
await typeInto("input-bulk-add", geneNames.join(","));
|
await typeInto("input-bulk-add", geneNames.join(","));
|
||||||
await page.keyboard.press("Enter");
|
await page.keyboard.press("Enter");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertCategoryDoesNotExist(categoryName) {
|
export async function assertCategoryDoesNotExist(categoryName: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const result = await isElementPresent(
|
const result = await isElementPresent(
|
||||||
getTestId(`${categoryName}:category-label`)
|
getTestId(`${categoryName}:category-label`)
|
||||||
);
|
);
|
||||||
@@ -480,7 +514,7 @@ export async function logout() {
|
|||||||
await waitByID("log-in");
|
await waitByID("log-in");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitUntilFormFieldStable(selector) {
|
async function waitUntilFormFieldStable(selector: any) {
|
||||||
const MAX_RETRY = 10;
|
const MAX_RETRY = 10;
|
||||||
const WAIT_FOR_MS = 200;
|
const WAIT_FOR_MS = 200;
|
||||||
|
|
||||||
@@ -58,10 +58,12 @@ describe("metadata loads", () => {
|
|||||||
const categories = await getAllCategoriesAndCounts(label);
|
const categories = await getAllCategoriesAndCounts(label);
|
||||||
|
|
||||||
expect(Object.keys(categories)).toMatchObject(
|
expect(Object.keys(categories)).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
Object.keys(data.categorical[label])
|
Object.keys(data.categorical[label])
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(Object.values(categories)).toMatchObject(
|
expect(Object.values(categories)).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
Object.values(data.categorical[label])
|
Object.values(data.categorical[label])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -159,10 +161,12 @@ describe("subset", () => {
|
|||||||
const categories = await getAllCategoriesAndCounts(label);
|
const categories = await getAllCategoriesAndCounts(label);
|
||||||
|
|
||||||
expect(Object.keys(categories)).toMatchObject(
|
expect(Object.keys(categories)).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
Object.keys(data.subset.categorical[label])
|
Object.keys(data.subset.categorical[label])
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(Object.values(categories)).toMatchObject(
|
expect(Object.values(categories)).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
Object.values(data.subset.categorical[label])
|
Object.values(data.subset.categorical[label])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -195,6 +199,7 @@ describe("clipping", () => {
|
|||||||
test("clip continuous", async () => {
|
test("clip continuous", async () => {
|
||||||
await goToPage(appUrlBase);
|
await goToPage(appUrlBase);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||||
await clip(data.clip.min, data.clip.max);
|
await clip(data.clip.min, data.clip.max);
|
||||||
const histBrushableAreaId = `histogram-${data.clip.metadata}-plot-brushable-area`;
|
const histBrushableAreaId = `histogram-${data.clip.metadata}-plot-brushable-area`;
|
||||||
const coords = await calcDragCoordinates(
|
const coords = await calcDragCoordinates(
|
||||||
@@ -254,6 +259,7 @@ describe("centroid labels", () => {
|
|||||||
const generatedLabels = await getAllByClass("centroid-label");
|
const generatedLabels = await getAllByClass("centroid-label");
|
||||||
// Number of labels generated should be equal to size of the object
|
// Number of labels generated should be equal to size of the object
|
||||||
expect(generatedLabels).toHaveLength(
|
expect(generatedLabels).toHaveLength(
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
Object.keys(data.categorical[label]).length
|
Object.keys(data.categorical[label]).length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -275,6 +281,7 @@ describe("graph overlay", () => {
|
|||||||
data.pan["coordinates-as-percent"]
|
data.pan["coordinates-as-percent"]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
const categoryValue = Object.keys(data.categorical[category])[0];
|
const categoryValue = Object.keys(data.categorical[category])[0];
|
||||||
const initialCoordinates = await getElementCoordinates(
|
const initialCoordinates = await getElementCoordinates(
|
||||||
`${categoryValue}-centroid-label`
|
`${categoryValue}-centroid-label`
|
||||||
+18
-8
@@ -76,7 +76,7 @@ const brushThisGeneGeneset = "brush_this_gene";
|
|||||||
const geneBrushedCellCount = "109";
|
const geneBrushedCellCount = "109";
|
||||||
const subsetGeneBrushedCellCount = "96";
|
const subsetGeneBrushedCellCount = "96";
|
||||||
|
|
||||||
async function setup(config) {
|
async function setup(config: any) {
|
||||||
await goToPage(appUrlBase);
|
await goToPage(appUrlBase);
|
||||||
|
|
||||||
if (config.categoricalAnno) {
|
if (config.categoricalAnno) {
|
||||||
@@ -150,7 +150,7 @@ describe.each([
|
|||||||
await expect(page).toClick(getTestClass("pop-1-geneset-expand"));
|
await expect(page).toClick(getTestClass("pop-1-geneset-expand"));
|
||||||
|
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
(selector) => !document.querySelector(selector),
|
(selector: any) => !document.querySelector(selector),
|
||||||
{},
|
{},
|
||||||
getTestClass("gene-loading-spinner")
|
getTestClass("gene-loading-spinner")
|
||||||
);
|
);
|
||||||
@@ -165,7 +165,7 @@ describe.each([
|
|||||||
await expect(page).toClick(getTestClass("pop-2-geneset-expand"));
|
await expect(page).toClick(getTestClass("pop-2-geneset-expand"));
|
||||||
|
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
(selector) => !document.querySelector(selector),
|
(selector: any) => !document.querySelector(selector),
|
||||||
{},
|
{},
|
||||||
getTestClass("gene-loading-spinner")
|
getTestClass("gene-loading-spinner")
|
||||||
);
|
);
|
||||||
@@ -362,8 +362,11 @@ describe.each([
|
|||||||
expect(actualLabelName).toBe(expectedLabelName);
|
expect(actualLabelName).toBe(expectedLabelName);
|
||||||
expect(actualLabelCount).toBe(expectedLabelCount);
|
expect(actualLabelCount).toBe(expectedLabelCount);
|
||||||
|
|
||||||
async function getInnerText(element, className) {
|
async function getInnerText(element: any, className: any) {
|
||||||
return element.$eval(getTestClass(className), (node) => node?.innerText);
|
return element.$eval(
|
||||||
|
getTestClass(className),
|
||||||
|
(node: any) => node?.innerText
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -388,7 +391,9 @@ describe.each([
|
|||||||
`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`
|
`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
expect(await result.evaluate((node) => node.innerText)).toBe(
|
expect(await result.evaluate((node) => node.innerText)).toBe(
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'boolean' cannot be used as an index type.
|
||||||
data.categoryLabel.newCount.bySubsetConfig[config.withSubset]
|
data.categoryLabel.newCount.bySubsetConfig[config.withSubset]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -448,6 +453,7 @@ describe.each([
|
|||||||
await createLabel(perTestCategoryName, labelName);
|
await createLabel(perTestCategoryName, labelName);
|
||||||
await assertLabelExists(perTestCategoryName, labelName);
|
await assertLabelExists(perTestCategoryName, labelName);
|
||||||
await clickOn("undo");
|
await clickOn("undo");
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
await assertLabelDoesNotExist(perTestCategoryName);
|
await assertLabelDoesNotExist(perTestCategoryName);
|
||||||
await clickOn("redo");
|
await clickOn("redo");
|
||||||
await assertLabelExists(perTestCategoryName, labelName);
|
await assertLabelExists(perTestCategoryName, labelName);
|
||||||
@@ -457,10 +463,12 @@ describe.each([
|
|||||||
await setup(config);
|
await setup(config);
|
||||||
|
|
||||||
await deleteLabel(perTestCategoryName, perTestLabelName);
|
await deleteLabel(perTestCategoryName, perTestLabelName);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
await assertLabelDoesNotExist(perTestCategoryName);
|
await assertLabelDoesNotExist(perTestCategoryName);
|
||||||
await clickOn("undo");
|
await clickOn("undo");
|
||||||
await assertLabelExists(perTestCategoryName, perTestLabelName);
|
await assertLabelExists(perTestCategoryName, perTestLabelName);
|
||||||
await clickOn("redo");
|
await clickOn("redo");
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
await assertLabelDoesNotExist(perTestCategoryName);
|
await assertLabelDoesNotExist(perTestCategoryName);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -523,9 +531,10 @@ describe.each([
|
|||||||
expect(result).toMatchSnapshot();
|
expect(result).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
async function assertCategoryExists(categoryName) {
|
async function assertCategoryExists(categoryName: any) {
|
||||||
const handle = await waitByID(`${categoryName}:category-label`);
|
const handle = await waitByID(`${categoryName}:category-label`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const result = await handle.evaluate((node) =>
|
const result = await handle.evaluate((node) =>
|
||||||
node.getAttribute("aria-label")
|
node.getAttribute("aria-label")
|
||||||
);
|
);
|
||||||
@@ -533,7 +542,7 @@ describe.each([
|
|||||||
return expect(result).toBe(categoryName);
|
return expect(result).toBe(categoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function assertLabelExists(categoryName, labelName) {
|
async function assertLabelExists(categoryName: any, labelName: any) {
|
||||||
await expect(page).toMatchElement(
|
await expect(page).toMatchElement(
|
||||||
getTestId(`${categoryName}:category-expand`)
|
getTestId(`${categoryName}:category-expand`)
|
||||||
);
|
);
|
||||||
@@ -545,11 +554,12 @@ describe.each([
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
await previous.evaluate((node) => node.getAttribute("aria-label"))
|
await previous.evaluate((node) => node.getAttribute("aria-label"))
|
||||||
).toBe(labelName);
|
).toBe(labelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function assertLabelDoesNotExist(categoryName, labelName) {
|
async function assertLabelDoesNotExist(categoryName: any, labelName: any) {
|
||||||
await expandCategory(categoryName);
|
await expandCategory(categoryName);
|
||||||
const result = await page.$(
|
const result = await page.$(
|
||||||
`[data-testid='categorical-value-${categoryName}-${labelName}']`
|
`[data-testid='categorical-value-${categoryName}-${labelName}']`
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"testRunner": "jest-circus/runner",
|
"testRunner": "jest-circus/runner",
|
||||||
"preset": "jest-puppeteer",
|
"preset": "jest-puppeteer",
|
||||||
"testMatch": ["**/__tests__/**/?(*.)(spec|test).js?(x)"],
|
"testMatch": ["**/__tests__/**/?(*.)(spec|test).ts?(x)"],
|
||||||
"setupFiles": ["../setupMissingGlobals.js"],
|
"setupFiles": ["../setupMissingGlobals.ts"],
|
||||||
"setupFilesAfterEnv": ["expect-puppeteer", "./puppeteer.setup.js"],
|
"setupFilesAfterEnv": ["expect-puppeteer", "./puppeteer.setup.ts"],
|
||||||
"globalSetup": "../globalSetup.js",
|
"globalSetup": "../globalSetup.ts",
|
||||||
"globalTeardown": "jest-environment-puppeteer/teardown",
|
"globalTeardown": "jest-environment-puppeteer/teardown",
|
||||||
"testEnvironment": "./screenshot_env.js"
|
"testEnvironment": "./screenshot_env.js"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ beforeEach(async () => {
|
|||||||
const userAgent = await browser.userAgent();
|
const userAgent = await browser.userAgent();
|
||||||
await page.setUserAgent(`${userAgent}bot`);
|
await page.setUserAgent(`${userAgent}bot`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2341) FIXME: Property '_client' is private and only accessible ... Remove this comment to see the full error message
|
||||||
await page._client.send("Animation.setPlaybackRate", { playbackRate: 12 });
|
await page._client.send("Animation.setPlaybackRate", { playbackRate: 12 });
|
||||||
|
|
||||||
page.on("pageerror", (err) => {
|
page.on("pageerror", (err) => {
|
||||||
@@ -49,7 +50,7 @@ beforeEach(async () => {
|
|||||||
}
|
}
|
||||||
const errorMsgText = await Promise.all(
|
const errorMsgText = await Promise.all(
|
||||||
// TODO can we do this without internal properties?
|
// TODO can we do this without internal properties?
|
||||||
msg.args().map((arg) => arg._remoteObject.description)
|
msg.args().map((arg: any) => arg._remoteObject.description)
|
||||||
);
|
);
|
||||||
throw new Error(`Console error: ${errorMsgText}`);
|
throw new Error(`Console error: ${errorMsgText}`);
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,31 @@
|
|||||||
/* eslint-disable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
|
/* eslint-disable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
|
||||||
export function getTestId(id) {
|
export function getTestId(id: any) {
|
||||||
return `[data-testid='${id}']`;
|
return `[data-testid='${id}']`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTestClass(className) {
|
export function getTestClass(className: any) {
|
||||||
return `[data-testclass='${className}']`;
|
return `[data-testclass='${className}']`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitByID(testId, props = {}) {
|
export async function waitByID(testId: any, props = {}) {
|
||||||
return page.waitForSelector(getTestId(testId), props);
|
return page.waitForSelector(getTestId(testId), props);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitByClass(testClass, props = {}) {
|
export async function waitByClass(testClass: any, props = {}) {
|
||||||
return page.waitForSelector(`[data-testclass='${testClass}']`, props);
|
return page.waitForSelector(`[data-testclass='${testClass}']`, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitForAllByIds(testIds) {
|
export async function waitForAllByIds(testIds: any) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
testIds.map((testId) => page.waitForSelector(getTestId(testId)))
|
testIds.map((testId: any) => page.waitForSelector(getTestId(testId)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllByClass(testClass) {
|
export async function getAllByClass(testClass: any) {
|
||||||
return page.$$(`[data-testclass=${testClass}]`);
|
return page.$$(`[data-testclass=${testClass}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function typeInto(testId, text) {
|
export async function typeInto(testId: any, text: any) {
|
||||||
// blueprint's typeahead is treating typing weird, clicking & waiting first solves this
|
// blueprint's typeahead is treating typing weird, clicking & waiting first solves this
|
||||||
// only works for text without special characters
|
// only works for text without special characters
|
||||||
await waitByID(testId);
|
await waitByID(testId);
|
||||||
@@ -36,7 +36,7 @@ export async function typeInto(testId, text) {
|
|||||||
await page.type(selector, text);
|
await page.type(selector, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clearInputAndTypeInto(testId, text) {
|
export async function clearInputAndTypeInto(testId: any, text: any) {
|
||||||
await waitByID(testId);
|
await waitByID(testId);
|
||||||
const selector = getTestId(testId);
|
const selector = getTestId(testId);
|
||||||
// only works for text without special characters
|
// only works for text without special characters
|
||||||
@@ -49,7 +49,7 @@ export async function clearInputAndTypeInto(testId, text) {
|
|||||||
await page.type(selector, text);
|
await page.type(selector, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickOn(testId, options = {}) {
|
export async function clickOn(testId: any, options = {}) {
|
||||||
await expect(page).toClick(getTestId(testId), options);
|
await expect(page).toClick(getTestId(testId), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ export async function clickOn(testId, options = {}) {
|
|||||||
* (thuang): There are times when Puppeteer clicks on a button and the page doesn't respond.
|
* (thuang): There are times when Puppeteer clicks on a button and the page doesn't respond.
|
||||||
* So I added clickOnUntil() to retry clicking until a given condition is met.
|
* So I added clickOnUntil() to retry clicking until a given condition is met.
|
||||||
*/
|
*/
|
||||||
export async function clickOnUntil(testId, assert) {
|
export async function clickOnUntil(testId: any, assert: any) {
|
||||||
const MAX_RETRY = 10;
|
const MAX_RETRY = 10;
|
||||||
const WAIT_FOR_MS = 200;
|
const WAIT_FOR_MS = 200;
|
||||||
|
|
||||||
@@ -81,19 +81,19 @@ export async function clickOnUntil(testId, assert) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getOneElementInnerHTML(selector, options = {}) {
|
export async function getOneElementInnerHTML(selector: any, options = {}) {
|
||||||
await page.waitForSelector(selector, options);
|
await page.waitForSelector(selector, options);
|
||||||
|
|
||||||
return page.$eval(selector, (el) => el.innerHTML);
|
return page.$eval(selector, (el) => el.innerHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getOneElementInnerText(selector) {
|
export async function getOneElementInnerText(selector: any) {
|
||||||
expect(page).toMatchElement(selector);
|
expect(page).toMatchElement(selector);
|
||||||
|
|
||||||
return page.$eval(selector, (el) => el.innerText);
|
return page.$eval(selector, (el) => (el as any).innerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getElementCoordinates(testId) {
|
export async function getElementCoordinates(testId: any) {
|
||||||
return page.$eval(getTestId(testId), (elem) => {
|
return page.$eval(getTestId(testId), (elem) => {
|
||||||
const { left, top } = elem.getBoundingClientRect();
|
const { left, top } = elem.getBoundingClientRect();
|
||||||
return [left, top];
|
return [left, top];
|
||||||
@@ -101,12 +101,14 @@ export async function getElementCoordinates(testId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function clickTermsOfService() {
|
async function clickTermsOfService() {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
if (!(await isElementPresent(getTestId("tos-cookies-accept")))) return;
|
if (!(await isElementPresent(getTestId("tos-cookies-accept")))) return;
|
||||||
|
|
||||||
await clickOn("tos-cookies-accept");
|
await clickOn("tos-cookies-accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function nameNewAnnotation() {
|
async function nameNewAnnotation() {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
if (await isElementPresent(getTestId("annotation-dialog"))) {
|
if (await isElementPresent(getTestId("annotation-dialog"))) {
|
||||||
await typeInto("new-annotation-name", "ignoreE2E");
|
await typeInto("new-annotation-name", "ignoreE2E");
|
||||||
await clickOn("submit-annotation");
|
await clickOn("submit-annotation");
|
||||||
@@ -116,7 +118,7 @@ async function nameNewAnnotation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function goToPage(url) {
|
export async function goToPage(url: any) {
|
||||||
await page.goto(url, {
|
await page.goto(url, {
|
||||||
waitUntil: "networkidle0",
|
waitUntil: "networkidle0",
|
||||||
});
|
});
|
||||||
@@ -125,7 +127,8 @@ export async function goToPage(url) {
|
|||||||
await clickTermsOfService();
|
await clickTermsOfService();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isElementPresent(selector, options) {
|
export async function isElementPresent(selector: any, options: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 2.
|
||||||
return Boolean(await page.$(selector, options));
|
return Boolean(await page.$(selector, options));
|
||||||
}
|
}
|
||||||
/* eslint-enable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
|
/* eslint-enable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
|
||||||
@@ -2,6 +2,7 @@ const PuppeteerEnvironment = require("jest-environment-puppeteer");
|
|||||||
require("jest-circus");
|
require("jest-circus");
|
||||||
const ENV_DEFAULT = require("../../../environment.default.json");
|
const ENV_DEFAULT = require("../../../environment.default.json");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2451) FIXME: Cannot redeclare block-scoped variable 'takeScreen... Remove this comment to see the full error message
|
||||||
const takeScreenshot = require("./takeScreenshot");
|
const takeScreenshot = require("./takeScreenshot");
|
||||||
|
|
||||||
class ScreenshotEnvironment extends PuppeteerEnvironment {
|
class ScreenshotEnvironment extends PuppeteerEnvironment {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-ignore FIXME revisit from ts-migrate
|
||||||
const {
|
const {
|
||||||
SecretsManagerClient,
|
SecretsManagerClient,
|
||||||
GetSecretValueCommand,
|
GetSecretValueCommand,
|
||||||
+12
-2
@@ -20,7 +20,12 @@ describe("cascade", () => {
|
|||||||
const reducer = cascadeReducers([
|
const reducer = cascadeReducers([
|
||||||
[
|
[
|
||||||
"foo",
|
"foo",
|
||||||
(currentState, action, nextSharedState, prevSharedState) => {
|
(
|
||||||
|
currentState: any,
|
||||||
|
action: any,
|
||||||
|
nextSharedState: any,
|
||||||
|
prevSharedState: any
|
||||||
|
) => {
|
||||||
expect(currentState).toBeUndefined();
|
expect(currentState).toBeUndefined();
|
||||||
expect(action).toEqual(topLevelAction);
|
expect(action).toEqual(topLevelAction);
|
||||||
expect(nextSharedState).toStrictEqual({});
|
expect(nextSharedState).toStrictEqual({});
|
||||||
@@ -30,7 +35,12 @@ describe("cascade", () => {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
"bar",
|
"bar",
|
||||||
(currentState, action, nextSharedState, prevSharedState) => {
|
(
|
||||||
|
currentState: any,
|
||||||
|
action: any,
|
||||||
|
nextSharedState: any,
|
||||||
|
prevSharedState: any
|
||||||
|
) => {
|
||||||
expect(currentState).toBeUndefined();
|
expect(currentState).toBeUndefined();
|
||||||
expect(action).toEqual(topLevelAction);
|
expect(action).toEqual(topLevelAction);
|
||||||
expect(nextSharedState).toStrictEqual({ foo: 0 });
|
expect(nextSharedState).toStrictEqual({ foo: 0 });
|
||||||
+2
@@ -501,6 +501,7 @@ describe("geneset: set tid", () => {
|
|||||||
test("not a number error", () => {
|
test("not a number error", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
genesetsReducer(
|
genesetsReducer(
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number' is not assignable to type 'undefined... Remove this comment to see the full error message
|
||||||
{ lastTid: 1 },
|
{ lastTid: 1 },
|
||||||
{
|
{
|
||||||
type: "geneset: set tid",
|
type: "geneset: set tid",
|
||||||
@@ -513,6 +514,7 @@ describe("geneset: set tid", () => {
|
|||||||
test("decrement error", () => {
|
test("decrement error", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
genesetsReducer(
|
genesetsReducer(
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number' is not assignable to type 'undefined... Remove this comment to see the full error message
|
||||||
{ lastTid: 1 },
|
{ lastTid: 1 },
|
||||||
{
|
{
|
||||||
type: "geneset: set tid",
|
type: "geneset: set tid",
|
||||||
+4
-3
@@ -2,6 +2,7 @@ import undoable from "../../src/reducers/undoable";
|
|||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
test("no keys", () => {
|
test("no keys", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2-3 arguments, but got 1.
|
||||||
expect(() => undoable(() => {})).toThrow();
|
expect(() => undoable(() => {})).toThrow();
|
||||||
expect(() => undoable(() => {}, null)).toThrow();
|
expect(() => undoable(() => {}, null)).toThrow();
|
||||||
expect(() => undoable(() => {}, [])).toThrow();
|
expect(() => undoable(() => {}, [])).toThrow();
|
||||||
@@ -23,7 +24,7 @@ describe("create", () => {
|
|||||||
describe("undo", () => {
|
describe("undo", () => {
|
||||||
test("expected state modifications", () => {
|
test("expected state modifications", () => {
|
||||||
const initialState = { a: 0, b: 1000 };
|
const initialState = { a: 0, b: 1000 };
|
||||||
const reducer = (state) => {
|
const reducer = (state: any) => {
|
||||||
return { a: state.a + 1, b: state.b + 1 };
|
return { a: state.a + 1, b: state.b + 1 };
|
||||||
};
|
};
|
||||||
const undoableReducer = undoable(reducer, ["a"]);
|
const undoableReducer = undoable(reducer, ["a"]);
|
||||||
@@ -43,10 +44,10 @@ describe("undo", () => {
|
|||||||
|
|
||||||
describe("redo", () => {
|
describe("redo", () => {
|
||||||
const initialState = { a: 0, b: 1000 };
|
const initialState = { a: 0, b: 1000 };
|
||||||
const reducer = (state) => {
|
const reducer = (state: any) => {
|
||||||
return { a: state.a + 1, b: state.b + 1 };
|
return { a: state.a + 1, b: state.b + 1 };
|
||||||
};
|
};
|
||||||
let UR;
|
let UR: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
UR = undoable(reducer, ["a"]);
|
UR = undoable(reducer, ["a"]);
|
||||||
@@ -5,5 +5,6 @@ the jest test environment).
|
|||||||
|
|
||||||
import { TextDecoder, TextEncoder } from "util";
|
import { TextDecoder, TextEncoder } from "util";
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'typeof TextDecoder' is not assignable to typ... Remove this comment to see the full error message
|
||||||
global.TextDecoder = TextDecoder;
|
global.TextDecoder = TextDecoder;
|
||||||
global.TextEncoder = TextEncoder;
|
global.TextEncoder = TextEncoder;
|
||||||
+22
-17
@@ -14,10 +14,11 @@ import { Dataframe } from "../../../src/util/dataframe";
|
|||||||
enableFetchMocks();
|
enableFetchMocks();
|
||||||
|
|
||||||
describe("AnnoMatrix", () => {
|
describe("AnnoMatrix", () => {
|
||||||
let annoMatrix;
|
let annoMatrix: any;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
fetch.resetMocks(); // reset all fetch mocking state
|
(fetch as any).resetMocks(); // reset all fetch mocking state
|
||||||
|
// reset all fetch mocking state
|
||||||
annoMatrix = new AnnoMatrixLoader(
|
annoMatrix = new AnnoMatrixLoader(
|
||||||
serverMocks.baseDataURL,
|
serverMocks.baseDataURL,
|
||||||
serverMocks.schema.schema
|
serverMocks.schema.schema
|
||||||
@@ -36,7 +37,7 @@ describe("AnnoMatrix", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("simple single column fetch", async () => {
|
test("simple single column fetch", async () => {
|
||||||
fetch.once(serverMocks.annotationsObs(["name_0"]));
|
(fetch as any).once(serverMocks.annotationsObs(["name_0"]));
|
||||||
|
|
||||||
const df = await annoMatrix.fetch("obs", "name_0");
|
const df = await annoMatrix.fetch("obs", "name_0");
|
||||||
expect(df).toBeInstanceOf(Dataframe);
|
expect(df).toBeInstanceOf(Dataframe);
|
||||||
@@ -45,7 +46,7 @@ describe("AnnoMatrix", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("simple multi column fetch", async () => {
|
test("simple multi column fetch", async () => {
|
||||||
fetch
|
(fetch as any)
|
||||||
.once(serverMocks.annotationsObs(["name_0"]))
|
.once(serverMocks.annotationsObs(["name_0"]))
|
||||||
.once(serverMocks.annotationsObs(["n_genes"]));
|
.once(serverMocks.annotationsObs(["n_genes"]));
|
||||||
|
|
||||||
@@ -55,9 +56,11 @@ describe("AnnoMatrix", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("fetch from field", () => {
|
describe("fetch from field", () => {
|
||||||
const getLastTwo = async (field) => {
|
const getLastTwo = async (field: any) => {
|
||||||
const columnNames = annoMatrix.getMatrixColumns(field).slice(-2);
|
const columnNames = annoMatrix.getMatrixColumns(field).slice(-2);
|
||||||
fetch.mockResponses(...columnNames.map(() => serverMocks.responder));
|
(fetch as any).mockResponses(
|
||||||
|
...columnNames.map(() => serverMocks.responder)
|
||||||
|
);
|
||||||
await expect(
|
await expect(
|
||||||
annoMatrix.fetch(field, columnNames)
|
annoMatrix.fetch(field, columnNames)
|
||||||
).resolves.toBeInstanceOf(Dataframe);
|
).resolves.toBeInstanceOf(Dataframe);
|
||||||
@@ -70,19 +73,19 @@ describe("AnnoMatrix", () => {
|
|||||||
|
|
||||||
test("fetch - test all query forms", async () => {
|
test("fetch - test all query forms", async () => {
|
||||||
// single string is a column name
|
// single string is a column name
|
||||||
fetch.once(serverMocks.annotationsObs(["n_genes"]));
|
(fetch as any).once(serverMocks.annotationsObs(["n_genes"]));
|
||||||
await expect(annoMatrix.fetch("obs", "n_genes")).resolves.toBeInstanceOf(
|
await expect(annoMatrix.fetch("obs", "n_genes")).resolves.toBeInstanceOf(
|
||||||
Dataframe
|
Dataframe
|
||||||
);
|
);
|
||||||
|
|
||||||
// array of column names, expecting n_genes to be cached.
|
// array of column names, expecting n_genes to be cached.
|
||||||
fetch.once(serverMocks.annotationsObs(["percent_mito"]));
|
(fetch as any).once(serverMocks.annotationsObs(["percent_mito"]));
|
||||||
await expect(
|
await expect(
|
||||||
annoMatrix.fetch("obs", ["n_genes", "percent_mito"])
|
annoMatrix.fetch("obs", ["n_genes", "percent_mito"])
|
||||||
).resolves.toBeInstanceOf(Dataframe);
|
).resolves.toBeInstanceOf(Dataframe);
|
||||||
|
|
||||||
// more complex value filter query, enumerated
|
// more complex value filter query, enumerated
|
||||||
fetch.once(serverMocks.responder);
|
(fetch as any).once(serverMocks.responder);
|
||||||
await expect(
|
await expect(
|
||||||
annoMatrix.fetch("X", {
|
annoMatrix.fetch("X", {
|
||||||
where: {
|
where: {
|
||||||
@@ -95,7 +98,7 @@ describe("AnnoMatrix", () => {
|
|||||||
|
|
||||||
// more complex value filter query, range
|
// more complex value filter query, range
|
||||||
const varIndex = annoMatrix.schema.annotations.var.index;
|
const varIndex = annoMatrix.schema.annotations.var.index;
|
||||||
fetch
|
(fetch as any)
|
||||||
.once(
|
.once(
|
||||||
serverMocks.withExpected("/data/var", [[`var:${varIndex}`, "SUMO3"]])
|
serverMocks.withExpected("/data/var", [[`var:${varIndex}`, "SUMO3"]])
|
||||||
)
|
)
|
||||||
@@ -171,7 +174,7 @@ describe("AnnoMatrix", () => {
|
|||||||
expect(am1.nObs).toEqual(am2.nObs);
|
expect(am1.nObs).toEqual(am2.nObs);
|
||||||
expect(am1.nVar).toEqual(am2.nVar);
|
expect(am1.nVar).toEqual(am2.nVar);
|
||||||
|
|
||||||
fetch
|
(fetch as any)
|
||||||
.once(serverMocks.annotationsObs(["n_genes"]))
|
.once(serverMocks.annotationsObs(["n_genes"]))
|
||||||
.once(serverMocks.annotationsObs(["n_genes"]));
|
.once(serverMocks.annotationsObs(["n_genes"]));
|
||||||
const ng1 = await am1.fetch("obs", "n_genes");
|
const ng1 = await am1.fetch("obs", "n_genes");
|
||||||
@@ -185,9 +188,10 @@ describe("AnnoMatrix", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("add/drop column", () => {
|
describe("add/drop column", () => {
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'base' implicitly has an 'any' type.
|
||||||
async function addDrop(base) {
|
async function addDrop(base) {
|
||||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(base.fetch("obs", "foo")).rejects.toThrow(
|
await expect(base.fetch("obs", "foo")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -212,7 +216,7 @@ describe("AnnoMatrix", () => {
|
|||||||
const am2 = am1.dropObsColumn("foo");
|
const am2 = am1.dropObsColumn("foo");
|
||||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||||
expect(am2.getMatrixColumns("obs")).not.toContain("foo");
|
expect(am2.getMatrixColumns("obs")).not.toContain("foo");
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(am2.fetch("obs", "foo")).rejects.toThrow(
|
await expect(am2.fetch("obs", "foo")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -235,14 +239,14 @@ describe("AnnoMatrix", () => {
|
|||||||
const am4 = clip(am3, 0, 1);
|
const am4 = clip(am3, 0, 1);
|
||||||
await addDrop(am4);
|
await addDrop(am4);
|
||||||
|
|
||||||
fetch.mockResponse(serverMocks.responder);
|
(fetch as any).mockResponse(serverMocks.responder);
|
||||||
|
|
||||||
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
||||||
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
||||||
await am3.fetch("obs", am3.getMatrixColumns("obs"));
|
await am3.fetch("obs", am3.getMatrixColumns("obs"));
|
||||||
await am4.fetch("obs", am4.getMatrixColumns("obs"));
|
await am4.fetch("obs", am4.getMatrixColumns("obs"));
|
||||||
|
|
||||||
fetch.resetMocks();
|
(fetch as any).resetMocks();
|
||||||
|
|
||||||
await addDrop(am1);
|
await addDrop(am1);
|
||||||
await addDrop(am2);
|
await addDrop(am2);
|
||||||
@@ -252,6 +256,7 @@ describe("AnnoMatrix", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("setObsColumnValues", () => {
|
describe("setObsColumnValues", () => {
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'base' implicitly has an 'any' type.
|
||||||
async function addSetDrop(base) {
|
async function addSetDrop(base) {
|
||||||
/* add column */
|
/* add column */
|
||||||
let am = base.addObsColumn(
|
let am = base.addObsColumn(
|
||||||
@@ -287,7 +292,7 @@ describe("AnnoMatrix", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/* drop column */
|
/* drop column */
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
am = am1.dropObsColumn("test");
|
am = am1.dropObsColumn("test");
|
||||||
await expect(am.fetch("obs", "test")).rejects.toThrow(
|
await expect(am.fetch("obs", "test")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
@@ -308,7 +313,7 @@ describe("AnnoMatrix", () => {
|
|||||||
const am3 = isubset(annoMatrix, [10, 1, 0, 30, 2]);
|
const am3 = isubset(annoMatrix, [10, 1, 0, 30, 2]);
|
||||||
await addSetDrop(am3);
|
await addSetDrop(am3);
|
||||||
|
|
||||||
fetch.mockResponse(serverMocks.responder);
|
(fetch as any).mockResponse(serverMocks.responder);
|
||||||
|
|
||||||
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
||||||
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
||||||
+60
-36
@@ -17,11 +17,12 @@ import { rangeFill } from "../../../src/util/range";
|
|||||||
enableFetchMocks();
|
enableFetchMocks();
|
||||||
|
|
||||||
describe("AnnoMatrixCrossfilter", () => {
|
describe("AnnoMatrixCrossfilter", () => {
|
||||||
let annoMatrix;
|
let annoMatrix: any;
|
||||||
let crossfilter;
|
let crossfilter: any;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
fetch.resetMocks(); // reset all fetch mocking state
|
(fetch as any).resetMocks(); // reset all fetch mocking state
|
||||||
|
// reset all fetch mocking state
|
||||||
annoMatrix = new AnnoMatrixLoader(
|
annoMatrix = new AnnoMatrixLoader(
|
||||||
serverMocks.baseDataURL,
|
serverMocks.baseDataURL,
|
||||||
serverMocks.schema.schema
|
serverMocks.schema.schema
|
||||||
@@ -67,7 +68,9 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
crossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
crossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
|
|
||||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
(fetch as any).once(
|
||||||
|
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||||
|
);
|
||||||
let newCrossfilter = await crossfilter.select("obs", "louvain", {
|
let newCrossfilter = await crossfilter.select("obs", "louvain", {
|
||||||
mode: "none",
|
mode: "none",
|
||||||
});
|
});
|
||||||
@@ -76,7 +79,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
expect(
|
expect(
|
||||||
newCrossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
newCrossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(fetch.mock.calls).toHaveLength(1);
|
expect((fetch as any).mock.calls).toHaveLength(1);
|
||||||
|
|
||||||
newCrossfilter = await crossfilter.select("obs", "louvain", {
|
newCrossfilter = await crossfilter.select("obs", "louvain", {
|
||||||
mode: "all",
|
mode: "all",
|
||||||
@@ -87,7 +90,9 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
test("simple column select", async () => {
|
test("simple column select", async () => {
|
||||||
let xfltr;
|
let xfltr;
|
||||||
|
|
||||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
(fetch as any).once(
|
||||||
|
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||||
|
);
|
||||||
xfltr = await crossfilter.select("obs", "louvain", {
|
xfltr = await crossfilter.select("obs", "louvain", {
|
||||||
mode: "exact",
|
mode: "exact",
|
||||||
values: ["NK cells", "B cells"],
|
values: ["NK cells", "B cells"],
|
||||||
@@ -105,6 +110,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
expect(xfltr.allSelectedLabels()).toEqual(
|
expect(xfltr.allSelectedLabels()).toEqual(
|
||||||
Int32Array.from(
|
Int32Array.from(
|
||||||
obsLouvain.reduce((acc, val, idx) => {
|
obsLouvain.reduce((acc, val, idx) => {
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number' is not assignable to par... Remove this comment to see the full error message
|
||||||
if (val === "NK cells" || val === "B cells") acc.push(idx);
|
if (val === "NK cells" || val === "B cells") acc.push(idx);
|
||||||
return acc;
|
return acc;
|
||||||
}, [])
|
}, [])
|
||||||
@@ -124,10 +130,11 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
const values = df.col("louvain").asArray();
|
const values = df.col("louvain").asArray();
|
||||||
const selected = xfltr.allSelectedMask();
|
const selected = xfltr.allSelectedMask();
|
||||||
values.every(
|
values.every(
|
||||||
(val, idx) => !["NK cells", "B cells"].includes(val) !== !selected[idx]
|
(val: any, idx: any) =>
|
||||||
|
!["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||||
);
|
);
|
||||||
|
|
||||||
fetch.once(
|
(fetch as any).once(
|
||||||
serverMocks.dataframeResponse(["n_genes"], [new Int32Array(obsNGenes)])
|
serverMocks.dataframeResponse(["n_genes"], [new Int32Array(obsNGenes)])
|
||||||
);
|
);
|
||||||
xfltr = await xfltr.select("obs", "n_genes", {
|
xfltr = await xfltr.select("obs", "n_genes", {
|
||||||
@@ -146,6 +153,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
val < 500 &&
|
val < 500 &&
|
||||||
(louvain === "NK cells" || louvain === "B cells")
|
(louvain === "NK cells" || louvain === "B cells")
|
||||||
)
|
)
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number' is not assignable to par... Remove this comment to see the full error message
|
||||||
acc.push(idx);
|
acc.push(idx);
|
||||||
return acc;
|
return acc;
|
||||||
}, [])
|
}, [])
|
||||||
@@ -160,7 +168,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
const varIndex = annoMatrix.schema.annotations.var.index;
|
const varIndex = annoMatrix.schema.annotations.var.index;
|
||||||
|
|
||||||
const { nObs } = annoMatrix.schema.dataframe;
|
const { nObs } = annoMatrix.schema.dataframe;
|
||||||
fetch.once(
|
(fetch as any).once(
|
||||||
serverMocks.dataframeResponse(
|
serverMocks.dataframeResponse(
|
||||||
["TEST"],
|
["TEST"],
|
||||||
[rangeFill(new Float32Array(nObs), 0, 0.1)]
|
[rangeFill(new Float32Array(nObs), 0, 0.1)]
|
||||||
@@ -196,14 +204,16 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
const values = df.icol(0).asArray();
|
const values = df.icol(0).asArray();
|
||||||
const selected = xfltr.allSelectedMask();
|
const selected = xfltr.allSelectedMask();
|
||||||
values.every((val, idx) => !(val >= 0 && val <= 50) !== !selected[idx]);
|
values.every(
|
||||||
expect(selected.reduce((acc, val) => (val ? acc + 1 : acc), 0)).toEqual(
|
(val: any, idx: any) => !(val >= 0 && val <= 50) !== !selected[idx]
|
||||||
xfltr.countSelected()
|
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
selected.reduce((acc: any, val: any) => (val ? acc + 1 : acc), 0)
|
||||||
|
).toEqual(xfltr.countSelected());
|
||||||
});
|
});
|
||||||
|
|
||||||
test("spatial column select", async () => {
|
test("spatial column select", async () => {
|
||||||
fetch.once(
|
(fetch as any).once(
|
||||||
serverMocks.dataframeResponse(
|
serverMocks.dataframeResponse(
|
||||||
["umap_0", "umap_1"],
|
["umap_0", "umap_1"],
|
||||||
[Float32Array.from(embUmap[0]), Float32Array.from(embUmap[1])]
|
[Float32Array.from(embUmap[0]), Float32Array.from(embUmap[1])]
|
||||||
@@ -222,6 +232,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
test("select on subset", async () => {
|
test("select on subset", async () => {
|
||||||
const mask = new Uint8Array(annoMatrix.nObs).fill(0);
|
const mask = new Uint8Array(annoMatrix.nObs).fill(0);
|
||||||
for (let i = 0; i < mask.length; i += 2) {
|
for (let i = 0; i < mask.length; i += 2) {
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'number'.
|
||||||
mask[i] = true;
|
mask[i] = true;
|
||||||
}
|
}
|
||||||
const annoMatrixSubset = isubsetMask(annoMatrix, mask);
|
const annoMatrixSubset = isubsetMask(annoMatrix, mask);
|
||||||
@@ -230,7 +241,9 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
let xfltr = new AnnoMatrixObsCrossfilter(annoMatrixSubset);
|
let xfltr = new AnnoMatrixObsCrossfilter(annoMatrixSubset);
|
||||||
expect(xfltr.countSelected()).toEqual(annoMatrixSubset.nObs);
|
expect(xfltr.countSelected()).toEqual(annoMatrixSubset.nObs);
|
||||||
|
|
||||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
(fetch as any).once(
|
||||||
|
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||||
|
);
|
||||||
xfltr = await xfltr.select("obs", "louvain", {
|
xfltr = await xfltr.select("obs", "louvain", {
|
||||||
mode: "exact",
|
mode: "exact",
|
||||||
values: ["NK cells", "B cells"],
|
values: ["NK cells", "B cells"],
|
||||||
@@ -243,7 +256,8 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
const values = df.col("louvain").asArray();
|
const values = df.col("louvain").asArray();
|
||||||
const selected = xfltr.allSelectedMask();
|
const selected = xfltr.allSelectedMask();
|
||||||
values.every(
|
values.every(
|
||||||
(val, idx) => !["NK cells", "B cells"].includes(val) !== !selected[idx]
|
(val: any, idx: any) =>
|
||||||
|
!["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -256,7 +270,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
"unable to obsSelect upon the var dimension"
|
"unable to obsSelect upon the var dimension"
|
||||||
);
|
);
|
||||||
|
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(crossfilter.select("obs", "foo")).rejects.toThrow(
|
await expect(crossfilter.select("obs", "foo")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -267,24 +281,27 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
/*
|
/*
|
||||||
test the matrix mutators via crossfilter proxy
|
test the matrix mutators via crossfilter proxy
|
||||||
*/
|
*/
|
||||||
async function helperAddTestCol(cf, colName, colSchema = null) {
|
async function helperAddTestCol(cf: any, colName: any, colSchema = null) {
|
||||||
expect(
|
expect(
|
||||||
cf.annoMatrix.getMatrixColumns("obs").includes(colName)
|
cf.annoMatrix.getMatrixColumns("obs").includes(colName)
|
||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
|
|
||||||
if (colSchema === null) {
|
if (colSchema === null) {
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ name: any; type: string; categories: strin... Remove this comment to see the full error message
|
||||||
colSchema = {
|
colSchema = {
|
||||||
name: colName,
|
name: colName,
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
categories: ["toasty"],
|
categories: ["toasty"],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
colSchema.name = colName;
|
colSchema.name = colName;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const initValue = colSchema.categories[0];
|
const initValue = colSchema.categories[0];
|
||||||
const xfltr = cf.addObsColumn(colSchema, Array, initValue);
|
const xfltr = cf.addObsColumn(colSchema, Array, initValue);
|
||||||
expect(
|
expect(
|
||||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||||
(v) => v.name === colName
|
(v: any) => v.name === colName
|
||||||
)
|
)
|
||||||
).toHaveLength(1);
|
).toHaveLength(1);
|
||||||
const df = await xfltr.annoMatrix.fetch("obs", colName);
|
const df = await xfltr.annoMatrix.fetch("obs", colName);
|
||||||
@@ -314,7 +331,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||||
(v) => v.name === "foo"
|
(v: any) => v.name === "foo"
|
||||||
)
|
)
|
||||||
).toHaveLength(1);
|
).toHaveLength(1);
|
||||||
|
|
||||||
@@ -324,7 +341,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
df
|
df
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every((v) => v === "A")
|
.every((v: any) => v === "A")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
// check that we catch dups
|
// check that we catch dups
|
||||||
@@ -361,11 +378,11 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
xfltr = xfltr.dropObsColumn("foo");
|
xfltr = xfltr.dropObsColumn("foo");
|
||||||
expect(
|
expect(
|
||||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||||
(v) => v.name === "foo"
|
(v: any) => v.name === "foo"
|
||||||
)
|
)
|
||||||
).toHaveLength(0);
|
).toHaveLength(0);
|
||||||
expect(xfltr.annoMatrix.schema.annotations.obsByName.foo).toBeUndefined();
|
expect(xfltr.annoMatrix.schema.annotations.obsByName.foo).toBeUndefined();
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -378,7 +395,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
xfltr = xfltr.dropObsColumn("bar");
|
xfltr = xfltr.dropObsColumn("bar");
|
||||||
|
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -404,7 +421,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
type: "categorical",
|
type: "categorical",
|
||||||
});
|
});
|
||||||
|
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -419,7 +436,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
xfltr = xfltr.renameObsColumn("bar", "xyz");
|
xfltr = xfltr.renameObsColumn("bar", "xyz");
|
||||||
|
|
||||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||||
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
||||||
"unknown column name"
|
"unknown column name"
|
||||||
);
|
);
|
||||||
@@ -429,7 +446,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("addObsAnnoCategory", async () => {
|
test("addObsAnnoCategory", async () => {
|
||||||
let xfltr;
|
let xfltr: any;
|
||||||
|
|
||||||
// catch unknown or readonly columns
|
// catch unknown or readonly columns
|
||||||
expect(() => crossfilter.addObsAnnoCategory("louvain", "mumble")).toThrow(
|
expect(() => crossfilter.addObsAnnoCategory("louvain", "mumble")).toThrow(
|
||||||
@@ -440,6 +457,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
).toThrow("Unknown or readonly obs column");
|
).toThrow("Unknown or readonly obs column");
|
||||||
|
|
||||||
// add a column and then add category to it
|
// add a column and then add category to it
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||||
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
@@ -458,6 +476,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// now same, but ensure we have built an index before doing the operation
|
// now same, but ensure we have built an index before doing the operation
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||||
xfltr = await helperAddTestCol(crossfilter, "bar", {
|
xfltr = await helperAddTestCol(crossfilter, "bar", {
|
||||||
name: "bar",
|
name: "bar",
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
@@ -486,6 +505,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
crossfilter.removeObsAnnoCategory("undefined-name", "mumble")
|
crossfilter.removeObsAnnoCategory("undefined-name", "mumble")
|
||||||
).rejects.toThrow("Unknown or readonly obs column");
|
).rejects.toThrow("Unknown or readonly obs column");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||||
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
@@ -496,7 +516,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every((v) => v === "unassigned")
|
.every((v: any) => v === "unassigned")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
expect(xfltr.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||||
name: "foo",
|
name: "foo",
|
||||||
@@ -515,7 +535,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every((v) => v === "unassigned")
|
.every((v: any) => v === "unassigned")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||||
name: "foo",
|
name: "foo",
|
||||||
@@ -538,7 +558,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr2.annoMatrix.fetch("obs", "foo"))
|
(await xfltr2.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every((v) => v === "red")
|
.every((v: any) => v === "red")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(xfltr2.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
expect(xfltr2.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||||
name: "foo",
|
name: "foo",
|
||||||
@@ -556,6 +576,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
crossfilter.setObsColumnValues("undefined-name", [0], "mumble")
|
crossfilter.setObsColumnValues("undefined-name", [0], "mumble")
|
||||||
).rejects.toThrow("Unknown or readonly obs column");
|
).rejects.toThrow("Unknown or readonly obs column");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||||
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
@@ -573,7 +594,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every((v) => v === "unassigned")
|
.every((v: any) => v === "unassigned")
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
const xfltr1 = await xfltr.setObsColumnValues("foo", [0, 10], "purple");
|
const xfltr1 = await xfltr.setObsColumnValues("foo", [0, 10], "purple");
|
||||||
expect(
|
expect(
|
||||||
@@ -581,7 +602,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.every(
|
.every(
|
||||||
(v, i) =>
|
(v: any, i: any) =>
|
||||||
v === "unassigned" || (v === "purple" && (i === 0 || i === 10))
|
v === "unassigned" || (v === "purple" && (i === 0 || i === 10))
|
||||||
)
|
)
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
@@ -615,6 +636,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
crossfilter.resetObsColumnValues("undefined-name", "red", "blue")
|
crossfilter.resetObsColumnValues("undefined-name", "red", "blue")
|
||||||
).rejects.toThrow("Unknown or readonly obs column");
|
).rejects.toThrow("Unknown or readonly obs column");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||||
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
type: "categorical",
|
type: "categorical",
|
||||||
@@ -639,7 +661,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.filter((v) => v === "purple")
|
.filter((v: any) => v === "purple")
|
||||||
).toHaveLength(2);
|
).toHaveLength(2);
|
||||||
|
|
||||||
xfltr1 = await xfltr1.resetObsColumnValues("foo", "purple", "magenta");
|
xfltr1 = await xfltr1.resetObsColumnValues("foo", "purple", "magenta");
|
||||||
@@ -647,13 +669,13 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.filter((v) => v === "magenta")
|
.filter((v: any) => v === "magenta")
|
||||||
).toHaveLength(2);
|
).toHaveLength(2);
|
||||||
expect(
|
expect(
|
||||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||||
.col("foo")
|
.col("foo")
|
||||||
.asArray()
|
.asArray()
|
||||||
.filter((v) => v === "purple")
|
.filter((v: any) => v === "purple")
|
||||||
).toHaveLength(0);
|
).toHaveLength(0);
|
||||||
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||||
name: "foo",
|
name: "foo",
|
||||||
@@ -673,12 +695,14 @@ describe("AnnoMatrixCrossfilter", () => {
|
|||||||
describe("edge cases", () => {
|
describe("edge cases", () => {
|
||||||
test("transition from empty annoMatrix", async () => {
|
test("transition from empty annoMatrix", async () => {
|
||||||
// select before fetch needs to work
|
// select before fetch needs to work
|
||||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
(fetch as any).once(
|
||||||
|
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||||
|
);
|
||||||
const xfltr = await crossfilter.select("obs", "louvain", {
|
const xfltr = await crossfilter.select("obs", "louvain", {
|
||||||
mode: "exact",
|
mode: "exact",
|
||||||
values: "B cells",
|
values: "B cells",
|
||||||
});
|
});
|
||||||
expect(fetch.mock.calls).toHaveLength(1);
|
expect((fetch as any).mock.calls).toHaveLength(1);
|
||||||
expect(xfltr.obsCrossfilter.hasDimension("obs/louvain")).toBeTruthy();
|
expect(xfltr.obsCrossfilter.hasDimension("obs/louvain")).toBeTruthy();
|
||||||
expect(xfltr.obsCrossfilter.all()).toBe(xfltr.annoMatrix._cache.obs);
|
expect(xfltr.obsCrossfilter.all()).toBe(xfltr.annoMatrix._cache.obs);
|
||||||
expect(xfltr.countSelected()).toEqual(
|
expect(xfltr.countSelected()).toEqual(
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
export const baseDataURL = "https://a.fake.url/api/v0.2";
|
export const baseDataURL = "https://a.fake.url/api/v0.2";
|
||||||
|
|
||||||
window.CELLXGENE = {
|
(window as any).CELLXGENE = {
|
||||||
API: {
|
API: {
|
||||||
prefix: baseDataURL,
|
prefix: baseDataURL,
|
||||||
version: "v0.2/",
|
version: "v0.2/",
|
||||||
+41
-22
@@ -14,7 +14,7 @@ const indexedSchema = {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeMockColumn(s, length) {
|
function makeMockColumn(s: any, length: any) {
|
||||||
const { type } = s;
|
const { type } = s;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "int32":
|
case "int32":
|
||||||
@@ -37,20 +37,22 @@ function makeMockColumn(s, length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEncodedDataframe(colNames, length, colSchemas) {
|
function getEncodedDataframe(colNames: any, length: any, colSchemas: any) {
|
||||||
const colIndex = new KeyIndex(colNames);
|
const colIndex = new KeyIndex(colNames);
|
||||||
const columns = colSchemas.map((s) => makeMockColumn(s, length));
|
const columns = colSchemas.map((s: any) => makeMockColumn(s, length));
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
const df = new Dataframe([length, colNames.length], columns, null, colIndex);
|
const df = new Dataframe([length, colNames.length], columns, null, colIndex);
|
||||||
const body = encodeMatrixFBS(df);
|
const body = encodeMatrixFBS(df);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dataframeResponse(colNames, columns) {
|
export function dataframeResponse(colNames: any, columns: any) {
|
||||||
const colIndex = new KeyIndex(colNames);
|
const colIndex = new KeyIndex(colNames);
|
||||||
const df = new Dataframe(
|
const df = new Dataframe(
|
||||||
[columns[0].length, colNames.length],
|
[columns[0].length, colNames.length],
|
||||||
columns,
|
columns,
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
colIndex
|
colIndex
|
||||||
);
|
);
|
||||||
const body = encodeMatrixFBS(df);
|
const body = encodeMatrixFBS(df);
|
||||||
@@ -60,15 +62,19 @@ export function dataframeResponse(colNames, columns) {
|
|||||||
return () => Promise.resolve({ body, init: { status: 200, headers } });
|
return () => Promise.resolve({ body, init: { status: 200, headers } });
|
||||||
}
|
}
|
||||||
|
|
||||||
function annotationObsResponse(request) {
|
function annotationObsResponse(request: any) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const params = Array.from(url.searchParams.entries());
|
const params = Array.from((url.searchParams as any).entries());
|
||||||
const names = params
|
const names = params
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
.filter(([k]) => k === "annotation-name")
|
.filter(([k]) => k === "annotation-name")
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '([, v]: [any, any]) => any' is n... Remove this comment to see the full error message
|
||||||
.map(([, v]) => v);
|
.map(([, v]) => v);
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
if (!names.every((n) => indexedSchema.obsByName[n])) {
|
if (!names.every((n) => indexedSchema.obsByName[n])) {
|
||||||
return Promise.reject(new Error("bad obs annotation name in URL"));
|
return Promise.reject(new Error("bad obs annotation name in URL"));
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
const colSchemas = names.map((n) => indexedSchema.obsByName[n]);
|
const colSchemas = names.map((n) => indexedSchema.obsByName[n]);
|
||||||
const body = getEncodedDataframe(
|
const body = getEncodedDataframe(
|
||||||
names,
|
names,
|
||||||
@@ -85,15 +91,19 @@ function annotationObsResponse(request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function annotationVarResponse(request) {
|
function annotationVarResponse(request: any) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const params = Array.from(url.searchParams.entries());
|
const params = Array.from((url.searchParams as any).entries());
|
||||||
const names = params
|
const names = params
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
.filter(([k]) => k === "annotation-name")
|
.filter(([k]) => k === "annotation-name")
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '([, v]: [any, any]) => any' is n... Remove this comment to see the full error message
|
||||||
.map(([, v]) => v);
|
.map(([, v]) => v);
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
if (!names.every((n) => indexedSchema.varByName[n])) {
|
if (!names.every((n) => indexedSchema.varByName[n])) {
|
||||||
return Promise.reject(new Error("bad var annotation name in URL"));
|
return Promise.reject(new Error("bad var annotation name in URL"));
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
const colSchemas = names.map((n) => indexedSchema.varByName[n]);
|
const colSchemas = names.map((n) => indexedSchema.varByName[n]);
|
||||||
const body = getEncodedDataframe(
|
const body = getEncodedDataframe(
|
||||||
names,
|
names,
|
||||||
@@ -110,15 +120,19 @@ function annotationVarResponse(request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function layoutObsResponse(request) {
|
function layoutObsResponse(request: any) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const params = Array.from(url.searchParams.entries());
|
const params = Array.from((url.searchParams as any).entries());
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
const names = params.filter(([k]) => k === "layout-name").map(([, v]) => v);
|
const names = params.filter(([k]) => k === "layout-name").map(([, v]) => v);
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
if (!names.every((n) => indexedSchema.embByName[n])) {
|
if (!names.every((n) => indexedSchema.embByName[n])) {
|
||||||
return Promise.reject(new Error("bad layout name in URL"));
|
return Promise.reject(new Error("bad layout name in URL"));
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
const dims = names.map((n) => indexedSchema.embByName[n].dims).flat();
|
const dims = names.map((n) => indexedSchema.embByName[n].dims).flat();
|
||||||
const colSchemas = names
|
const colSchemas = names
|
||||||
|
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||||
.map((n) => [indexedSchema.embByName[n], indexedSchema.embByName[n]])
|
.map((n) => [indexedSchema.embByName[n], indexedSchema.embByName[n]])
|
||||||
.flat();
|
.flat();
|
||||||
const body = getEncodedDataframe(
|
const body = getEncodedDataframe(
|
||||||
@@ -136,11 +150,11 @@ function layoutObsResponse(request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataVarResponse(request) {
|
function dataVarResponse(request: any) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const params = Array.from(url.searchParams.entries());
|
const params = Array.from((url.searchParams as any).entries());
|
||||||
|
|
||||||
const colNames = params.map((v) => `${v[0]}/${v[1]}`);
|
const colNames = params.map((v) => `${(v as any)[0]}/${(v as any)[1]}`);
|
||||||
const colSchemas = colNames.map(() => schema.schema.dataframe);
|
const colSchemas = colNames.map(() => schema.schema.dataframe);
|
||||||
const body = getEncodedDataframe(
|
const body = getEncodedDataframe(
|
||||||
colNames,
|
colNames,
|
||||||
@@ -157,7 +171,7 @@ function dataVarResponse(request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function responder(request) {
|
export function responder(request: any) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const { pathname } = url;
|
const { pathname } = url;
|
||||||
if (pathname.endsWith("/annotations/obs")) {
|
if (pathname.endsWith("/annotations/obs")) {
|
||||||
@@ -175,25 +189,30 @@ export function responder(request) {
|
|||||||
return Promise.reject(new Error("bad URL"));
|
return Promise.reject(new Error("bad URL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withExpected(expectedURL, expectedParams) {
|
export function withExpected(expectedURL: any, expectedParams: any) {
|
||||||
/*
|
/*
|
||||||
Do some additional error checking
|
Do some additional error checking
|
||||||
*/
|
*/
|
||||||
return (request) => {
|
return (request: any) => {
|
||||||
// if URL is bogus, reject the promise
|
// if URL is bogus, reject the promise
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
if (!url.pathname.endsWith(expectedURL)) {
|
if (!url.pathname.endsWith(expectedURL)) {
|
||||||
return Promise.reject(new Error("Unexpected URL!"));
|
return Promise.reject(new Error("Unexpected URL!"));
|
||||||
}
|
}
|
||||||
const params = Array.from(url.searchParams.entries()).sort(
|
const params = Array.from((url.searchParams as any).entries()).sort(
|
||||||
(a, b) => a[0] < b[0]
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '(a: unknown, b: unknown) => bool... Remove this comment to see the full error message
|
||||||
|
(a, b) => (a as any)[0] < (b as any)[0]
|
||||||
);
|
);
|
||||||
expectedParams = expectedParams.slice().sort((a, b) => a[0] < b[0]);
|
expectedParams = expectedParams
|
||||||
|
.slice()
|
||||||
|
.sort((a: any, b: any) => a[0] < b[0]);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
params.length !== expectedParams.length ||
|
params.length !== expectedParams.length ||
|
||||||
!params.every(
|
!params.every(
|
||||||
(p, i) => p[0] === expectedParams[i][0] && p[1] === expectedParams[i][1]
|
(p, i) =>
|
||||||
|
(p as any)[0] === expectedParams[i][0] &&
|
||||||
|
(p as any)[1] === expectedParams[i][1]
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return Promise.reject(new Error("unexpected name requested in URL"));
|
return Promise.reject(new Error("unexpected name requested in URL"));
|
||||||
@@ -203,9 +222,9 @@ export function withExpected(expectedURL, expectedParams) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function annotationsObs(names) {
|
export function annotationsObs(names: any) {
|
||||||
return withExpected(
|
return withExpected(
|
||||||
"/annotations/obs",
|
"/annotations/obs",
|
||||||
names.map((name) => ["annotation-name", name])
|
names.map((name: any) => ["annotation-name", name])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+8
-3
@@ -218,10 +218,15 @@ describe("whereCache", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(wc.where.field.queryField.has("queryColumn")).toEqual(true);
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
expect(wc.where.field.queryField.get("queryColumn")).toBeInstanceOf(Map);
|
expect((wc.where as any).field.queryField.has("queryColumn")).toEqual(true);
|
||||||
expect(
|
expect(
|
||||||
wc.where.field.queryField.get("queryColumn").has("queryValue")
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
|
(wc.where as any).field.queryField.get("queryColumn")
|
||||||
|
).toBeInstanceOf(Map);
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
|
(wc.where as any).field.queryField.get("queryColumn").has("queryValue")
|
||||||
).toEqual(true);
|
).toEqual(true);
|
||||||
expect(_whereCacheGet(wc, schema, "field", query)).toEqual([0, 1, 2]);
|
expect(_whereCacheGet(wc, schema, "field", query)).toEqual([0, 1, 2]);
|
||||||
});
|
});
|
||||||
@@ -8,9 +8,9 @@ import { indexEntireSchema } from "../../src/util/stateManager/schemaHelpers";
|
|||||||
import { _normalizeCategoricalSchema } from "../../src/annoMatrix/schema";
|
import { _normalizeCategoricalSchema } from "../../src/annoMatrix/schema";
|
||||||
|
|
||||||
describe("centroid", () => {
|
describe("centroid", () => {
|
||||||
let schema;
|
let schema: any;
|
||||||
let obsAnnotations;
|
let obsAnnotations: any;
|
||||||
let obsLayout;
|
let obsLayout: any;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
schema = indexEntireSchema(cloneDeep(REST.schema.schema));
|
schema = indexEntireSchema(cloneDeep(REST.schema.schema));
|
||||||
@@ -44,7 +44,7 @@ describe("centroid", () => {
|
|||||||
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
||||||
];
|
];
|
||||||
|
|
||||||
centroidResult.forEach((coordinate) => {
|
centroidResult.forEach((coordinate: any) => {
|
||||||
expect(coordinate).toEqual(expectedResult);
|
expect(coordinate).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -68,7 +68,7 @@ describe("centroid", () => {
|
|||||||
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
||||||
];
|
];
|
||||||
|
|
||||||
centroidResult.forEach((coordinate) => {
|
centroidResult.forEach((coordinate: any) => {
|
||||||
expect(coordinate).toEqual(expectedResult);
|
expect(coordinate).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+40
-2
@@ -29,6 +29,7 @@ describe("dataframe constructor", () => {
|
|||||||
const df = new Dataframe.Dataframe(
|
const df = new Dataframe.Dataframe(
|
||||||
[3, 2],
|
[3, 2],
|
||||||
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([2, 1, 0]),
|
new Dataframe.DenseInt32Index([2, 1, 0]),
|
||||||
new Dataframe.KeyIndex(["A", "B"])
|
new Dataframe.KeyIndex(["A", "B"])
|
||||||
);
|
);
|
||||||
@@ -55,6 +56,7 @@ describe("simple data access", () => {
|
|||||||
new Float64Array([0.0, Number.NaN, Number.POSITIVE_INFINITY, 3.14159]),
|
new Float64Array([0.0, Number.NaN, Number.POSITIVE_INFINITY, 3.14159]),
|
||||||
["red", "blue", "green", "nan"],
|
["red", "blue", "green", "nan"],
|
||||||
],
|
],
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([3, 2, 1, 0]),
|
new Dataframe.DenseInt32Index([3, 2, 1, 0]),
|
||||||
new Dataframe.KeyIndex(["numbers", "colors"])
|
new Dataframe.KeyIndex(["numbers", "colors"])
|
||||||
);
|
);
|
||||||
@@ -139,10 +141,12 @@ describe("dataframe subsetting", () => {
|
|||||||
["red", "green", "blue"],
|
["red", "green", "blue"],
|
||||||
],
|
],
|
||||||
null, // identity index
|
null, // identity index
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||||
);
|
);
|
||||||
|
|
||||||
test("all rows, one column", () => {
|
test("all rows, one column", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfA = sourceDf.subset(null, ["colors"]);
|
const dfA = sourceDf.subset(null, ["colors"]);
|
||||||
expect(dfA).toBeDefined();
|
expect(dfA).toBeDefined();
|
||||||
expect(dfA.dims).toEqual([3, 1]);
|
expect(dfA.dims).toEqual([3, 1]);
|
||||||
@@ -158,6 +162,7 @@ describe("dataframe subsetting", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("all rows, two columns", () => {
|
test("all rows, two columns", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfB = sourceDf.subset(null, ["float32", "colors"]);
|
const dfB = sourceDf.subset(null, ["float32", "colors"]);
|
||||||
expect(dfB).toBeDefined();
|
expect(dfB).toBeDefined();
|
||||||
expect(dfB.dims).toEqual([3, 2]);
|
expect(dfB.dims).toEqual([3, 2]);
|
||||||
@@ -227,6 +232,7 @@ describe("dataframe subsetting", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("two rows, two colums", () => {
|
test("two rows, two colums", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfF = sourceDf.subset([0, 2], ["int32", "float32"]);
|
const dfF = sourceDf.subset([0, 2], ["int32", "float32"]);
|
||||||
expect(dfF).toBeDefined();
|
expect(dfF).toBeDefined();
|
||||||
expect(dfF.dims).toEqual([2, 2]);
|
expect(dfF.dims).toEqual([2, 2]);
|
||||||
@@ -236,6 +242,7 @@ describe("dataframe subsetting", () => {
|
|||||||
expect(dfF.colIndex.labels()).toEqual(["int32", "float32"]);
|
expect(dfF.colIndex.labels()).toEqual(["int32", "float32"]);
|
||||||
|
|
||||||
// reverse the row and column order
|
// reverse the row and column order
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfFr = sourceDf.subset([2, 0], ["float32", "int32"]);
|
const dfFr = sourceDf.subset([2, 0], ["float32", "int32"]);
|
||||||
expect(dfFr).toBeDefined();
|
expect(dfFr).toBeDefined();
|
||||||
expect(dfFr.dims).toEqual([2, 2]);
|
expect(dfFr.dims).toEqual([2, 2]);
|
||||||
@@ -248,6 +255,7 @@ describe("dataframe subsetting", () => {
|
|||||||
test("withRowIndex", () => {
|
test("withRowIndex", () => {
|
||||||
const df = sourceDf.subset(
|
const df = sourceDf.subset(
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
["int32", "float32"],
|
["int32", "float32"],
|
||||||
new Dataframe.DenseInt32Index([3, 2, 1])
|
new Dataframe.DenseInt32Index([3, 2, 1])
|
||||||
);
|
);
|
||||||
@@ -258,12 +266,15 @@ describe("dataframe subsetting", () => {
|
|||||||
|
|
||||||
test("withRowIndex error checks", () => {
|
test("withRowIndex error checks", () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
sourceDf.subset(null, ["red"], new Dataframe.IdentityInt32Index(1))
|
sourceDf.subset(null, ["red"], new Dataframe.IdentityInt32Index(1))
|
||||||
).toThrow(RangeError);
|
).toThrow(RangeError);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
sourceDf.subset(null, ["red"], new Dataframe.DenseInt32Index([0, 1]))
|
sourceDf.subset(null, ["red"], new Dataframe.DenseInt32Index([0, 1]))
|
||||||
).toThrow(RangeError);
|
).toThrow(RangeError);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
sourceDf.subset(null, ["red"], new Dataframe.KeyIndex([0, 1, 2, 3]))
|
sourceDf.subset(null, ["red"], new Dataframe.KeyIndex([0, 1, 2, 3]))
|
||||||
).toThrow(RangeError);
|
).toThrow(RangeError);
|
||||||
});
|
});
|
||||||
@@ -278,12 +289,14 @@ describe("dataframe subsetting", () => {
|
|||||||
new Float32Array([4.4, 5.5, 6.6]),
|
new Float32Array([4.4, 5.5, 6.6]),
|
||||||
["red", "green", "blue"],
|
["red", "green", "blue"],
|
||||||
],
|
],
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([2, 4, 6]),
|
new Dataframe.DenseInt32Index([2, 4, 6]),
|
||||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||||
);
|
);
|
||||||
|
|
||||||
const dfA = sourceDf.isubsetMask(
|
const dfA = sourceDf.isubsetMask(
|
||||||
new Uint8Array([0, 1, 1]),
|
new Uint8Array([0, 1, 1]),
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'Uint8Array' is not assignable to... Remove this comment to see the full error message
|
||||||
new Uint8Array([1, 0, 0, 1])
|
new Uint8Array([1, 0, 0, 1])
|
||||||
);
|
);
|
||||||
expect(dfA.dims).toEqual([2, 2]);
|
expect(dfA.dims).toEqual([2, 2]);
|
||||||
@@ -303,6 +316,7 @@ describe("dataframe subsetting", () => {
|
|||||||
["red", "green", "blue"],
|
["red", "green", "blue"],
|
||||||
],
|
],
|
||||||
null, // identity index
|
null, // identity index
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -316,6 +330,7 @@ describe("dataframe subsetting", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("all rows, two cols", () => {
|
test("all rows, two cols", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfA = sourceDf.isubset(null, [1, 2]);
|
const dfA = sourceDf.isubset(null, [1, 2]);
|
||||||
expect(dfA.dims).toEqual([3, 2]);
|
expect(dfA.dims).toEqual([3, 2]);
|
||||||
expect(dfA.icol(0).asArray()).toEqual(["A", "B", "C"]);
|
expect(dfA.icol(0).asArray()).toEqual(["A", "B", "C"]);
|
||||||
@@ -361,6 +376,7 @@ describe("dataframe factories", () => {
|
|||||||
const dfA = new Dataframe.Dataframe(
|
const dfA = new Dataframe.Dataframe(
|
||||||
[3, 2],
|
[3, 2],
|
||||||
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([2, 1, 0]),
|
new Dataframe.DenseInt32Index([2, 1, 0]),
|
||||||
new Dataframe.KeyIndex(["A", "B"])
|
new Dataframe.KeyIndex(["A", "B"])
|
||||||
);
|
);
|
||||||
@@ -385,6 +401,7 @@ describe("dataframe factories", () => {
|
|||||||
[true, false],
|
[true, false],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors", "bools"])
|
new Dataframe.KeyIndex(["colors", "bools"])
|
||||||
);
|
);
|
||||||
const dfA = df.withCol("numbers", [1, 0]);
|
const dfA = df.withCol("numbers", [1, 0]);
|
||||||
@@ -408,6 +425,7 @@ describe("dataframe factories", () => {
|
|||||||
[true, false],
|
[true, false],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([74, 75])
|
new Dataframe.DenseInt32Index([74, 75])
|
||||||
);
|
);
|
||||||
const dfA = df.withCol(72, [1, 0]);
|
const dfA = df.withCol(72, [1, 0]);
|
||||||
@@ -433,6 +451,7 @@ describe("dataframe factories", () => {
|
|||||||
[true, false],
|
[true, false],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([74, 75])
|
new Dataframe.DenseInt32Index([74, 75])
|
||||||
);
|
);
|
||||||
const dfA = df.withCol(999, [1, 0]);
|
const dfA = df.withCol(999, [1, 0]);
|
||||||
@@ -541,6 +560,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -549,11 +569,14 @@ describe("dataframe factories", () => {
|
|||||||
[3, 1],
|
[3, 1],
|
||||||
[["red", "blue", "green"]],
|
[["red", "blue", "green"]],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colorsA"])
|
new Dataframe.KeyIndex(["colorsA"])
|
||||||
);
|
);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
expect(() => dfA.withColsFrom(dfB)).toThrow(RangeError);
|
expect(() => dfA.withColsFrom(dfB)).toThrow(RangeError);
|
||||||
|
|
||||||
/* duplicate labels should throw an error */
|
/* duplicate labels should throw an error */
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
expect(() => dfA.withColsFrom(dfA)).toThrow(Error);
|
expect(() => dfA.withColsFrom(dfA)).toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -564,15 +587,18 @@ describe("dataframe factories", () => {
|
|||||||
[2, 1],
|
[2, 1],
|
||||||
[["red", "blue"]],
|
[["red", "blue"]],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors"])
|
new Dataframe.KeyIndex(["colors"])
|
||||||
);
|
);
|
||||||
const dfB = new Dataframe.Dataframe(
|
const dfB = new Dataframe.Dataframe(
|
||||||
[2, 1],
|
[2, 1],
|
||||||
[[true, false]],
|
[[true, false]],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["bools"])
|
new Dataframe.KeyIndex(["bools"])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const dfLikeA = dfEmpty.withColsFrom(dfA);
|
const dfLikeA = dfEmpty.withColsFrom(dfA);
|
||||||
expect(dfLikeA).toBeDefined();
|
expect(dfLikeA).toBeDefined();
|
||||||
expect(dfLikeA.dims).toEqual(dfA.dims);
|
expect(dfLikeA.dims).toEqual(dfA.dims);
|
||||||
@@ -581,6 +607,7 @@ describe("dataframe factories", () => {
|
|||||||
expect(dfLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
expect(dfLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
||||||
expect(dfLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
expect(dfLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const dfAlsoLikeA = dfA.withColsFrom(dfEmpty);
|
const dfAlsoLikeA = dfA.withColsFrom(dfEmpty);
|
||||||
expect(dfAlsoLikeA).toBeDefined();
|
expect(dfAlsoLikeA).toBeDefined();
|
||||||
expect(dfAlsoLikeA.dims).toEqual(dfA.dims);
|
expect(dfAlsoLikeA.dims).toEqual(dfA.dims);
|
||||||
@@ -589,6 +616,7 @@ describe("dataframe factories", () => {
|
|||||||
expect(dfAlsoLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
expect(dfAlsoLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
||||||
expect(dfAlsoLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
expect(dfAlsoLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const dfC = dfA.withColsFrom(dfB);
|
const dfC = dfA.withColsFrom(dfB);
|
||||||
expect(dfC).toBeDefined();
|
expect(dfC).toBeDefined();
|
||||||
expect(dfC.dims).toEqual([2, 2]);
|
expect(dfC.dims).toEqual([2, 2]);
|
||||||
@@ -605,6 +633,7 @@ describe("dataframe factories", () => {
|
|||||||
[2, 1],
|
[2, 1],
|
||||||
[["red", "blue"]],
|
[["red", "blue"]],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors"])
|
new Dataframe.KeyIndex(["colors"])
|
||||||
);
|
);
|
||||||
const dfB = new Dataframe.Dataframe(
|
const dfB = new Dataframe.Dataframe(
|
||||||
@@ -615,6 +644,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -647,6 +677,7 @@ describe("dataframe factories", () => {
|
|||||||
[2, 1],
|
[2, 1],
|
||||||
[["red", "blue"]],
|
[["red", "blue"]],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors"])
|
new Dataframe.KeyIndex(["colors"])
|
||||||
);
|
);
|
||||||
const dfB = new Dataframe.Dataframe(
|
const dfB = new Dataframe.Dataframe(
|
||||||
@@ -657,6 +688,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -680,6 +712,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||||
);
|
);
|
||||||
const dfA = df.dropCol("colors");
|
const dfA = df.dropCol("colors");
|
||||||
@@ -751,6 +784,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||||
new Dataframe.DenseInt32Index([102, 101, 100])
|
new Dataframe.DenseInt32Index([102, 101, 100])
|
||||||
);
|
);
|
||||||
const dfA = df.dropCol(101);
|
const dfA = df.dropCol(101);
|
||||||
@@ -777,7 +811,7 @@ describe("dataframe factories", () => {
|
|||||||
new Float64Array(3).fill(1.1),
|
new Float64Array(3).fill(1.1),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
const dfB = dfA.mapColumns((col, idx) => {
|
const dfB = dfA.mapColumns((col: any, idx: any) => {
|
||||||
expect(dfA.icol(idx).asArray()).toBe(col);
|
expect(dfA.icol(idx).asArray()).toBe(col);
|
||||||
return col;
|
return col;
|
||||||
});
|
});
|
||||||
@@ -822,6 +856,7 @@ describe("dataframe factories", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["A", "B"])
|
new Dataframe.KeyIndex(["A", "B"])
|
||||||
);
|
);
|
||||||
const dfB = dfA.renameCol("B", "C");
|
const dfB = dfA.renameCol("B", "C");
|
||||||
@@ -834,7 +869,7 @@ describe("dataframe factories", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("dataframe col", () => {
|
describe("dataframe col", () => {
|
||||||
let df = null;
|
let df: any = null;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
df = new Dataframe.Dataframe(
|
df = new Dataframe.Dataframe(
|
||||||
[2, 2],
|
[2, 2],
|
||||||
@@ -843,6 +878,7 @@ describe("dataframe col", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["A", "B"])
|
new Dataframe.KeyIndex(["A", "B"])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1195,6 +1231,7 @@ describe("label indexing", () => {
|
|||||||
test("create", () => {
|
test("create", () => {
|
||||||
expect(Dataframe.isLabelIndex(idx)).toBeTruthy();
|
expect(Dataframe.isLabelIndex(idx)).toBeTruthy();
|
||||||
expect(() => new Dataframe.KeyIndex(["dup", "dup"])).toThrow(Error);
|
expect(() => new Dataframe.KeyIndex(["dup", "dup"])).toThrow(Error);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
expect(new Dataframe.KeyIndex().size()).toEqual(0);
|
expect(new Dataframe.KeyIndex().size()).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1367,6 +1404,7 @@ describe("corner cases", () => {
|
|||||||
[1, 0],
|
[1, 0],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["A", "B"])
|
new Dataframe.KeyIndex(["A", "B"])
|
||||||
);
|
);
|
||||||
|
|
||||||
+4
@@ -6,6 +6,7 @@ describe("Dataframe column histogram", () => {
|
|||||||
[3, 3],
|
[3, 3],
|
||||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ describe("Dataframe column histogram", () => {
|
|||||||
[3, 3],
|
[3, 3],
|
||||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ describe("Dataframe column histogram", () => {
|
|||||||
[3, 3],
|
[3, 3],
|
||||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,6 +71,7 @@ describe("Dataframe column histogram", () => {
|
|||||||
[3, 3],
|
[3, 3],
|
||||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||||
);
|
);
|
||||||
|
|
||||||
+6
-1
@@ -1,6 +1,6 @@
|
|||||||
import * as Dataframe from "../../../src/util/dataframe";
|
import * as Dataframe from "../../../src/util/dataframe";
|
||||||
|
|
||||||
function float32Conversion(f) {
|
function float32Conversion(f: any) {
|
||||||
return new Float32Array([f])[0];
|
return new Float32Array([f])[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@ describe("Dataframe column summary", () => {
|
|||||||
[1],
|
[1],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex([
|
new Dataframe.KeyIndex([
|
||||||
"name",
|
"name",
|
||||||
"nameString",
|
"nameString",
|
||||||
@@ -106,6 +107,7 @@ describe("Dataframe column summary", () => {
|
|||||||
[1, false, "0"],
|
[1, false, "0"],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex([
|
new Dataframe.KeyIndex([
|
||||||
"name",
|
"name",
|
||||||
"nameString",
|
"nameString",
|
||||||
@@ -174,6 +176,7 @@ describe("Dataframe column summary", () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
categorical: true,
|
categorical: true,
|
||||||
categories: expect.arrayContaining([1, false, "0"]),
|
categories: expect.arrayContaining([1, false, "0"]),
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
categoryCounts: new Map([
|
categoryCounts: new Map([
|
||||||
[1, 1],
|
[1, 1],
|
||||||
[false, 1],
|
[false, 1],
|
||||||
@@ -201,6 +204,7 @@ describe("Dataframe column summary", () => {
|
|||||||
[1, false, "0", "0"],
|
[1, false, "0", "0"],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex([
|
new Dataframe.KeyIndex([
|
||||||
"name",
|
"name",
|
||||||
"nameString",
|
"nameString",
|
||||||
@@ -269,6 +273,7 @@ describe("Dataframe column summary", () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
categorical: true,
|
categorical: true,
|
||||||
categories: expect.arrayContaining([1, false, "0"]),
|
categories: expect.arrayContaining([1, false, "0"]),
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
categoryCounts: new Map([
|
categoryCounts: new Map([
|
||||||
[1, 1],
|
[1, 1],
|
||||||
[false, 1],
|
[false, 1],
|
||||||
+3
-2
@@ -1,7 +1,7 @@
|
|||||||
import PromiseLimit from "../../src/util/promiseLimit";
|
import PromiseLimit from "../../src/util/promiseLimit";
|
||||||
import { range } from "../../src/util/range";
|
import { range } from "../../src/util/range";
|
||||||
|
|
||||||
const delay = (t) => new Promise((resolve) => setTimeout(resolve, t));
|
const delay = (t: any) => new Promise((resolve) => setTimeout(resolve, t));
|
||||||
|
|
||||||
describe("PromiseLimit", () => {
|
describe("PromiseLimit", () => {
|
||||||
test("simple evaluation, concurrency 1", async () => {
|
test("simple evaluation, concurrency 1", async () => {
|
||||||
@@ -51,7 +51,8 @@ describe("PromiseLimit", () => {
|
|||||||
running -= 1;
|
running -= 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
await Promise.all(range(10).map((i) => plimit.add(() => callback(i))));
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1.
|
||||||
|
await Promise.all(range(10).map((i: any) => plimit.add(() => callback(i))));
|
||||||
|
|
||||||
expect(maxRunning).toEqual(2);
|
expect(maxRunning).toEqual(2);
|
||||||
});
|
});
|
||||||
@@ -6,14 +6,20 @@ describe("range", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("range(stop)", () => {
|
test("range(stop)", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1.
|
||||||
expect(range(3)).toMatchObject([0, 1, 2]);
|
expect(range(3)).toMatchObject([0, 1, 2]);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1.
|
||||||
expect(range(0)).toMatchObject([]);
|
expect(range(0)).toMatchObject([]);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 1.
|
||||||
expect(range(1)).toMatchObject([0]);
|
expect(range(1)).toMatchObject([0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("range(start,stop)", () => {
|
test("range(start,stop)", () => {
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
|
||||||
expect(range(0, 0)).toMatchObject([]);
|
expect(range(0, 0)).toMatchObject([]);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
|
||||||
expect(range(0, 2)).toMatchObject([0, 1]);
|
expect(range(0, 2)).toMatchObject([0, 1]);
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
|
||||||
expect(range(4, 8)).toMatchObject([4, 5, 6, 7]);
|
expect(range(4, 8)).toMatchObject([4, 5, 6, 7]);
|
||||||
});
|
});
|
||||||
|
|
||||||
+13
-8
@@ -81,6 +81,7 @@ describe("categorical color helpers", () => {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
new Dataframe.KeyIndex(["continuousColumn", "categoricalColumn"])
|
new Dataframe.KeyIndex(["continuousColumn", "categoricalColumn"])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -95,6 +96,7 @@ describe("categorical color helpers", () => {
|
|||||||
const data = obsDataframe.col("categoricalColumn").asArray();
|
const data = obsDataframe.col("categoricalColumn").asArray();
|
||||||
const cats = schema.annotations.obsByName.categoricalColumn.categories;
|
const cats = schema.annotations.obsByName.categoricalColumn.categories;
|
||||||
for (let i = 0; i < schema.dataframe.nObs; i += 1) {
|
for (let i = 0; i < schema.dataframe.nObs; i += 1) {
|
||||||
|
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
||||||
expect(makeScale(ct.rgb[i])).toEqual(ct.scale(cats.indexOf(data[i])));
|
expect(makeScale(ct.rgb[i])).toEqual(ct.scale(cats.indexOf(data[i])));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -112,6 +114,7 @@ describe("categorical color helpers", () => {
|
|||||||
const data = obsDataframe.col("categoricalColumn").asArray();
|
const data = obsDataframe.col("categoricalColumn").asArray();
|
||||||
const cats = schemaClone.annotations.obsByName.categoricalColumn.categories;
|
const cats = schemaClone.annotations.obsByName.categoricalColumn.categories;
|
||||||
for (let i = 0; i < schemaClone.dataframe.nObs; i += 1) {
|
for (let i = 0; i < schemaClone.dataframe.nObs; i += 1) {
|
||||||
|
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
||||||
expect(makeScale(ct.rgb[i])).toEqual(ct.scale(cats.indexOf(data[i])));
|
expect(makeScale(ct.rgb[i])).toEqual(ct.scale(cats.indexOf(data[i])));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -122,7 +125,7 @@ describe("categorical color helpers", () => {
|
|||||||
Array.from(schema.annotations.obsByName.categoricalColumn.categories)
|
Array.from(schema.annotations.obsByName.categoricalColumn.categories)
|
||||||
);
|
);
|
||||||
const userDefinedColorTable = {
|
const userDefinedColorTable = {
|
||||||
categoricalColumn: shuffleCats.reduce((acc, label) => {
|
categoricalColumn: shuffleCats.reduce((acc: any, label: any) => {
|
||||||
acc[label] = randRGBColor();
|
acc[label] = randRGBColor();
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {}),
|
||||||
@@ -136,12 +139,14 @@ describe("categorical color helpers", () => {
|
|||||||
"categoricalColumn",
|
"categoricalColumn",
|
||||||
obsDataframe,
|
obsDataframe,
|
||||||
schema,
|
schema,
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{}' is not assignable to paramet... Remove this comment to see the full error message
|
||||||
userColors
|
userColors
|
||||||
);
|
);
|
||||||
expect(ct).toBeDefined();
|
expect(ct).toBeDefined();
|
||||||
const data = obsDataframe.col("categoricalColumn").asArray();
|
const data = obsDataframe.col("categoricalColumn").asArray();
|
||||||
for (let i = 0; i < schema.dataframe.nObs; i += 1) {
|
for (let i = 0; i < schema.dataframe.nObs; i += 1) {
|
||||||
expect(makeScale(ct.rgb[i])).toEqual(
|
expect(makeScale(ct.rgb[i])).toEqual(
|
||||||
|
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
||||||
ct.scale(cats.indexOf(data[i])).toString()
|
ct.scale(cats.indexOf(data[i])).toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -154,31 +159,31 @@ TODO:
|
|||||||
2. user defined colors
|
2. user defined colors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function indexSchema(schema) {
|
function indexSchema(schema: any) {
|
||||||
schema.annotations.obsByName = Object.fromEntries(
|
schema.annotations.obsByName = Object.fromEntries(
|
||||||
schema.annotations?.obs?.columns?.map((v) => [v.name, v]) ?? []
|
schema.annotations?.obs?.columns?.map((v: any) => [v.name, v]) ?? []
|
||||||
);
|
);
|
||||||
schema.annotations.varByName = Object.fromEntries(
|
schema.annotations.varByName = Object.fromEntries(
|
||||||
schema.annotations?.var?.columns?.map((v) => [v.name, v]) ?? []
|
schema.annotations?.var?.columns?.map((v: any) => [v.name, v]) ?? []
|
||||||
);
|
);
|
||||||
schema.layout.obsByName = Object.fromEntries(
|
schema.layout.obsByName = Object.fromEntries(
|
||||||
schema.layout?.obs?.map((v) => [v.name, v]) ?? []
|
schema.layout?.obs?.map((v: any) => [v.name, v]) ?? []
|
||||||
);
|
);
|
||||||
schema.layout.varByName = Object.fromEntries(
|
schema.layout.varByName = Object.fromEntries(
|
||||||
schema.layout?.var?.map((v) => [v.name, v]) ?? []
|
schema.layout?.var?.map((v: any) => [v.name, v]) ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeScale(rgb) {
|
function makeScale(rgb: any) {
|
||||||
// make a scale string from a rgb float triple
|
// make a scale string from a rgb float triple
|
||||||
return `rgb(${(rgb[0] * 255) >>> 0}, ${(rgb[1] * 255) >>> 0}, ${
|
return `rgb(${(rgb[0] * 255) >>> 0}, ${(rgb[1] * 255) >>> 0}, ${
|
||||||
(rgb[2] * 256) >>> 0
|
(rgb[2] * 256) >>> 0
|
||||||
})`;
|
})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shuffle(array) {
|
function shuffle(array: any) {
|
||||||
for (let i = array.length - 1; i > 0; i -= 1) {
|
for (let i = array.length - 1; i > 0; i -= 1) {
|
||||||
const j = (Math.random() * (i + 1)) >>> 0;
|
const j = (Math.random() * (i + 1)) >>> 0;
|
||||||
[array[i], array[j]] = [array[j], array[i]];
|
[array[i], array[j]] = [array[j], array[i]];
|
||||||
+1
@@ -24,6 +24,7 @@ describe("encode/decode", () => {
|
|||||||
expect(dfA.columns).toEqual(columns);
|
expect(dfA.columns).toEqual(columns);
|
||||||
|
|
||||||
const colIndex = new KeyIndex(["a", "b", "c", "d"]);
|
const colIndex = new KeyIndex(["a", "b", "c", "d"]);
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||||
const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex);
|
const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex);
|
||||||
const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx));
|
const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx));
|
||||||
expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims);
|
expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims);
|
||||||
+9
-2
@@ -75,6 +75,7 @@ const aSchemaResponse = {
|
|||||||
|
|
||||||
const anAnnotationsObsJSONResponse = {
|
const anAnnotationsObsJSONResponse = {
|
||||||
names: ["name", "field1", "field2", "field3", "field4"],
|
names: ["name", "field1", "field2", "field3", "field4"],
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
data: _()
|
data: _()
|
||||||
.range(nObs)
|
.range(nObs)
|
||||||
.map((idx) => [
|
.map((idx) => [
|
||||||
@@ -91,6 +92,7 @@ const anAnnotationsObsJSONResponse = {
|
|||||||
|
|
||||||
const anAnnotationsVarJSONResponse = {
|
const anAnnotationsVarJSONResponse = {
|
||||||
names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"],
|
names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"],
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
data: _()
|
data: _()
|
||||||
.range(nVar)
|
.range(nVar)
|
||||||
.map((idx) => [
|
.map((idx) => [
|
||||||
@@ -105,7 +107,7 @@ const anAnnotationsVarJSONResponse = {
|
|||||||
.value(),
|
.value(),
|
||||||
};
|
};
|
||||||
|
|
||||||
function encodeTypedArray(builder, uType, uData) {
|
function encodeTypedArray(builder: any, uType: any, uData: any) {
|
||||||
const uTypeName = NetEncoding.TypedArray[uType];
|
const uTypeName = NetEncoding.TypedArray[uType];
|
||||||
const ArrayType = NetEncoding[uTypeName];
|
const ArrayType = NetEncoding[uTypeName];
|
||||||
const dv = ArrayType.createDataVector(builder, uData);
|
const dv = ArrayType.createDataVector(builder, uData);
|
||||||
@@ -114,7 +116,7 @@ function encodeTypedArray(builder, uType, uData) {
|
|||||||
return builder.endObject();
|
return builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeMatrix(columns, colIndex = undefined) {
|
function encodeMatrix(columns: any, colIndex = undefined) {
|
||||||
/*
|
/*
|
||||||
IMPORTANT: this is not a general purpose encoder. in particular,
|
IMPORTANT: this is not a general purpose encoder. in particular,
|
||||||
it doesn't correctly handle all column index types, nor does it
|
it doesn't correctly handle all column index types, nor does it
|
||||||
@@ -123,6 +125,7 @@ function encodeMatrix(columns, colIndex = undefined) {
|
|||||||
encodeMatrixFBS in matrix.py is more general. This is used only
|
encodeMatrixFBS in matrix.py is more general. This is used only
|
||||||
as a testing santity check (alt implementation).
|
as a testing santity check (alt implementation).
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
const utf8Encoder = new TextEncoder("utf-8");
|
const utf8Encoder = new TextEncoder("utf-8");
|
||||||
const builder = new flatbuffers.Builder(1024);
|
const builder = new flatbuffers.Builder(1024);
|
||||||
const cols = map(columns, (carr) => {
|
const cols = map(columns, (carr) => {
|
||||||
@@ -172,11 +175,13 @@ function encodeMatrix(columns, colIndex = undefined) {
|
|||||||
|
|
||||||
const anAnnotationsObsFBSResponse = (() => {
|
const anAnnotationsObsFBSResponse = (() => {
|
||||||
const columns = zip(...anAnnotationsObsJSONResponse.data).slice(1);
|
const columns = zip(...anAnnotationsObsJSONResponse.data).slice(1);
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
return encodeMatrix(columns, anAnnotationsObsJSONResponse.names);
|
return encodeMatrix(columns, anAnnotationsObsJSONResponse.names);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const anAnnotationsVarFBSResponse = (() => {
|
const anAnnotationsVarFBSResponse = (() => {
|
||||||
const columns = zip(...anAnnotationsVarJSONResponse.data).slice(1);
|
const columns = zip(...anAnnotationsVarJSONResponse.data).slice(1);
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
return encodeMatrix(columns, anAnnotationsVarJSONResponse.names);
|
return encodeMatrix(columns, anAnnotationsVarJSONResponse.names);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -185,11 +190,13 @@ const aLayoutFBSResponse = (() => {
|
|||||||
new Float32Array(nObs).fill(Math.random()),
|
new Float32Array(nObs).fill(Math.random()),
|
||||||
new Float32Array(nObs).fill(Math.random()),
|
new Float32Array(nObs).fill(Math.random()),
|
||||||
];
|
];
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||||
return encodeMatrix(coords, ["umap_0", "umap_1"]);
|
return encodeMatrix(coords, ["umap_0", "umap_1"]);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const aDataObsResponse = {
|
const aDataObsResponse = {
|
||||||
var: [2, 4, 29],
|
var: [2, 4, 29],
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
obs: _()
|
obs: _()
|
||||||
.range(nObs)
|
.range(nObs)
|
||||||
.map((idx) => [idx, Math.random(), Math.random(), Math.random()])
|
.map((idx) => [idx, Math.random(), Math.random(), Math.random()])
|
||||||
+46
-16
@@ -126,7 +126,7 @@ const someData = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let payments = null;
|
let payments: any = null;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
payments = new Crossfilter(someData);
|
payments = new Crossfilter(someData);
|
||||||
});
|
});
|
||||||
@@ -138,7 +138,12 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
expect(payments.all()).toEqual(someData);
|
expect(payments.all()).toEqual(someData);
|
||||||
|
|
||||||
const p = payments
|
const p = payments
|
||||||
.addDimension("quantity", "scalar", (i, d) => d[i].quantity, Int32Array)
|
.addDimension(
|
||||||
|
"quantity",
|
||||||
|
"scalar",
|
||||||
|
(i: any, d: any) => d[i].quantity,
|
||||||
|
Int32Array
|
||||||
|
)
|
||||||
.select("quantity", { mode: "all" });
|
.select("quantity", { mode: "all" });
|
||||||
expect(p).toBeDefined();
|
expect(p).toBeDefined();
|
||||||
expect(p.all()).toEqual(someData);
|
expect(p.all()).toEqual(someData);
|
||||||
@@ -158,7 +163,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
const p2 = payments.addDimension(
|
const p2 = payments.addDimension(
|
||||||
"quantity",
|
"quantity",
|
||||||
"scalar",
|
"scalar",
|
||||||
(i, data) => data[i].quantity,
|
(i: any, data: any) => data[i].quantity,
|
||||||
Int32Array
|
Int32Array
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -175,10 +180,20 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
|
|
||||||
test("select all and none", () => {
|
test("select all and none", () => {
|
||||||
let p = payments
|
let p = payments
|
||||||
.addDimension("quantity", "scalar", (i, d) => d[i].quantity, Int32Array)
|
.addDimension(
|
||||||
.addDimension("tip", "scalar", (i, d) => d[i].tip, Float32Array)
|
"quantity",
|
||||||
.addDimension("total", "scalar", (i, d) => d[i].total, Float32Array)
|
"scalar",
|
||||||
.addDimension("type", "enum", (i, d) => d[i].type);
|
(i: any, d: any) => d[i].quantity,
|
||||||
|
Int32Array
|
||||||
|
)
|
||||||
|
.addDimension("tip", "scalar", (i: any, d: any) => d[i].tip, Float32Array)
|
||||||
|
.addDimension(
|
||||||
|
"total",
|
||||||
|
"scalar",
|
||||||
|
(i: any, d: any) => d[i].total,
|
||||||
|
Float32Array
|
||||||
|
)
|
||||||
|
.addDimension("type", "enum", (i: any, d: any) => d[i].type);
|
||||||
expect(p).toBeDefined();
|
expect(p).toBeDefined();
|
||||||
|
|
||||||
/* expect all records to be selected - default init state */
|
/* expect all records to be selected - default init state */
|
||||||
@@ -230,11 +245,21 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("scalar dimension", () => {
|
describe("scalar dimension", () => {
|
||||||
let p;
|
let p: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
p = payments
|
p = payments
|
||||||
.addDimension("quantity", "scalar", (i, d) => d[i].quantity, Int32Array)
|
.addDimension(
|
||||||
.addDimension("tip", "scalar", (i, d) => d[i].tip, Float32Array)
|
"quantity",
|
||||||
|
"scalar",
|
||||||
|
(i: any, d: any) => d[i].quantity,
|
||||||
|
Int32Array
|
||||||
|
)
|
||||||
|
.addDimension(
|
||||||
|
"tip",
|
||||||
|
"scalar",
|
||||||
|
(i: any, d: any) => d[i].tip,
|
||||||
|
Float32Array
|
||||||
|
)
|
||||||
.select("tip", { mode: "all" });
|
.select("tip", { mode: "all" });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -277,9 +302,9 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("enum dimension", () => {
|
describe("enum dimension", () => {
|
||||||
let p;
|
let p: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
p = payments.addDimension("type", "enum", (i, d) => d[i].type);
|
p = payments.addDimension("type", "enum", (i: any, d: any) => d[i].type);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("all", () => {
|
test("all", () => {
|
||||||
@@ -317,7 +342,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("spatial dimension", () => {
|
describe("spatial dimension", () => {
|
||||||
let p;
|
let p: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const X = someData.map((r) => r.coords[0]);
|
const X = someData.map((r) => r.coords[0]);
|
||||||
const Y = someData.map((r) => r.coords[1]);
|
const Y = someData.map((r) => r.coords[1]);
|
||||||
@@ -406,14 +431,19 @@ describe("ImmutableTypedCrossfilter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("non-finite scalars", () => {
|
describe("non-finite scalars", () => {
|
||||||
let p;
|
let p: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
p = payments
|
p = payments
|
||||||
.addDimension("quantity", "scalar", (i, d) => d[i].quantity, Int32Array)
|
.addDimension(
|
||||||
|
"quantity",
|
||||||
|
"scalar",
|
||||||
|
(i: any, d: any) => d[i].quantity,
|
||||||
|
Int32Array
|
||||||
|
)
|
||||||
.addDimension(
|
.addDimension(
|
||||||
"nonFinite",
|
"nonFinite",
|
||||||
"scalar",
|
"scalar",
|
||||||
(i, d) => d[i].nonFinite,
|
(i: any, d: any) => d[i].nonFinite,
|
||||||
Float32Array
|
Float32Array
|
||||||
)
|
)
|
||||||
.select("quantity", { mode: "all" });
|
.select("quantity", { mode: "all" });
|
||||||
+13
-5
@@ -15,7 +15,7 @@ paths for:
|
|||||||
const pInf = Number.POSITIVE_INFINITY;
|
const pInf = Number.POSITIVE_INFINITY;
|
||||||
const nInf = Number.NEGATIVE_INFINITY;
|
const nInf = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
function fillRange(arr, start = 0) {
|
function fillRange(arr: any, start = 0) {
|
||||||
const larr = arr;
|
const larr = arr;
|
||||||
for (let i = 0, len = larr.length; i < len; i += 1) {
|
for (let i = 0, len = larr.length; i < len; i += 1) {
|
||||||
larr[i] = i + start;
|
larr[i] = i + start;
|
||||||
@@ -23,7 +23,7 @@ function fillRange(arr, start = 0) {
|
|||||||
return larr;
|
return larr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillRand(arr) {
|
function fillRand(arr: any) {
|
||||||
for (let i = 0, len = arr.length; i < len; i += 1) {
|
for (let i = 0, len = arr.length; i < len; i += 1) {
|
||||||
arr[i] = Math.random();
|
arr[i] = Math.random();
|
||||||
}
|
}
|
||||||
@@ -48,16 +48,22 @@ describe("sortArray", () => {
|
|||||||
describe("finite numbers", () => {
|
describe("finite numbers", () => {
|
||||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
||||||
test(Type.name, () => {
|
test(Type.name, () => {
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
expect(sortArray(Type.from([6, 5, 4, 3, 2, 1, 0]))).toMatchObject(
|
expect(sortArray(Type.from([6, 5, 4, 3, 2, 1, 0]))).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
Type.from([0, 1, 2, 3, 4, 5, 6])
|
Type.from([0, 1, 2, 3, 4, 5, 6])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
expect(sortArray(Type.from([6, 5, 4, 3, 2, 1]))).toMatchObject(
|
expect(sortArray(Type.from([6, 5, 4, 3, 2, 1]))).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
Type.from([1, 2, 3, 4, 5, 6])
|
Type.from([1, 2, 3, 4, 5, 6])
|
||||||
);
|
);
|
||||||
|
|
||||||
const source = fillRand(new Type(1000));
|
const source = fillRand(new Type(1000));
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
expect(sortArray(Type.from(source))).toMatchObject(
|
expect(sortArray(Type.from(source))).toMatchObject(
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
Type.from(source).sort()
|
Type.from(source).sort()
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -130,22 +136,24 @@ describe("sortIndex", () => {
|
|||||||
describe("finite numbers", () => {
|
describe("finite numbers", () => {
|
||||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
||||||
test(Type.name, () => {
|
test(Type.name, () => {
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
const source1 = Type.from([6, 5, 4, 3, 2, 1, 0]);
|
const source1 = Type.from([6, 5, 4, 3, 2, 1, 0]);
|
||||||
const index1 = fillRange(new Uint32Array(source1.length));
|
const index1 = fillRange(new Uint32Array(source1.length));
|
||||||
expect(sortIndex(index1, source1)).toMatchObject(
|
expect(sortIndex(index1, source1)).toMatchObject(
|
||||||
index1.sort((a, b) => source1[a] - source1[b])
|
index1.sort((a: any, b: any) => source1[a] - source1[b])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||||
const source2 = Type.from([6, 5, 4, 3, 2, 1]);
|
const source2 = Type.from([6, 5, 4, 3, 2, 1]);
|
||||||
const index2 = fillRange(new Uint32Array(source2.length));
|
const index2 = fillRange(new Uint32Array(source2.length));
|
||||||
expect(sortIndex(index2, source2)).toMatchObject(
|
expect(sortIndex(index2, source2)).toMatchObject(
|
||||||
index2.sort((a, b) => source1[a] - source1[b])
|
index2.sort((a: any, b: any) => source1[a] - source1[b])
|
||||||
);
|
);
|
||||||
|
|
||||||
const source3 = fillRand(new Type(1000));
|
const source3 = fillRand(new Type(1000));
|
||||||
const index3 = fillRange(new Uint32Array(source3.length));
|
const index3 = fillRange(new Uint32Array(source3.length));
|
||||||
expect(sortIndex(index3, source3)).toMatchObject(
|
expect(sortIndex(index3, source3)).toMatchObject(
|
||||||
index3.sort((a, b) => source1[a] - source1[b])
|
index3.sort((a: any, b: any) => source1[a] - source1[b])
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@babel/preset-react",
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript",
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
"@babel/plugin-proposal-function-bind",
|
"@babel/plugin-proposal-function-bind",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@babel/preset-react",
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript"
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
"@babel/plugin-proposal-function-bind",
|
"@babel/plugin-proposal-function-bind",
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parser: "babel-eslint",
|
parser: "@typescript-eslint/parser",
|
||||||
extends: [
|
extends: [
|
||||||
"airbnb",
|
"airbnb-typescript",
|
||||||
"plugin:eslint-comments/recommended",
|
"plugin:eslint-comments/recommended",
|
||||||
"plugin:@blueprintjs/recommended",
|
"plugin:@blueprintjs/recommended",
|
||||||
"plugin:compat/recommended",
|
"plugin:compat/recommended",
|
||||||
"plugin:prettier/recommended",
|
"plugin:prettier/recommended",
|
||||||
"prettier",
|
|
||||||
],
|
],
|
||||||
settings: {
|
settings: {
|
||||||
// AbortController is not supported in iOS Safari 10.3, Chrome 61
|
// AbortController is not supported in iOS Safari 10.3, Chrome 61
|
||||||
@@ -32,18 +31,47 @@ module.exports = {
|
|||||||
jsx: true,
|
jsx: true,
|
||||||
generators: true,
|
generators: true,
|
||||||
},
|
},
|
||||||
|
project: "./tsconfig.json",
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"react/jsx-no-target-blank": "off",
|
"react/jsx-no-target-blank": "off",
|
||||||
"eslint-comments/require-description": ["error"],
|
"eslint-comments/require-description": ["error"],
|
||||||
"no-magic-numbers": "off",
|
"no-magic-numbers": "off",
|
||||||
|
"@typescript-eslint/no-magic-numbers": "off",
|
||||||
"no-nested-ternary": "off",
|
"no-nested-ternary": "off",
|
||||||
"func-style": "off",
|
"func-style": "off",
|
||||||
"arrow-parens": "off",
|
"arrow-parens": "off",
|
||||||
"no-use-before-define": "off",
|
"no-use-before-define": "off",
|
||||||
|
"@typescript-eslint/no-use-before-define": "off",
|
||||||
"react/jsx-filename-extension": "off",
|
"react/jsx-filename-extension": "off",
|
||||||
"comma-dangle": "off",
|
"comma-dangle": "off",
|
||||||
|
"@typescript-eslint/comma-dangle": "off",
|
||||||
"no-underscore-dangle": "off",
|
"no-underscore-dangle": "off",
|
||||||
|
// Override airbnb config to allow leading underscore
|
||||||
|
// https://github.com/iamturns/eslint-config-airbnb-typescript/blob/master/lib/shared.js#L35
|
||||||
|
"@typescript-eslint/naming-convention": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
selector: "class",
|
||||||
|
format: ["PascalCase"],
|
||||||
|
leadingUnderscore: "allow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "function",
|
||||||
|
format: ["camelCase", "PascalCase"],
|
||||||
|
leadingUnderscore: "allowSingleOrDouble",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "typeLike",
|
||||||
|
format: ["PascalCase"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "variable",
|
||||||
|
format: ["camelCase", "PascalCase", "UPPER_CASE"],
|
||||||
|
leadingUnderscore: "allowSingleOrDouble",
|
||||||
|
trailingUnderscore: "allowDouble",
|
||||||
|
},
|
||||||
|
],
|
||||||
"implicit-arrow-linebreak": "off",
|
"implicit-arrow-linebreak": "off",
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"spaced-comment": ["error", "always", { exceptions: ["*"] }],
|
"spaced-comment": ["error", "always", { exceptions: ["*"] }],
|
||||||
@@ -51,6 +79,7 @@ module.exports = {
|
|||||||
"object-curly-newline": ["error", { consistent: true }],
|
"object-curly-newline": ["error", { consistent: true }],
|
||||||
"react/prop-types": [0],
|
"react/prop-types": [0],
|
||||||
"space-before-function-paren": "off",
|
"space-before-function-paren": "off",
|
||||||
|
"@typescript-eslint/space-before-function-paren": "off",
|
||||||
"function-paren-newline": "off",
|
"function-paren-newline": "off",
|
||||||
"prefer-destructuring": ["error", { object: true, array: false }],
|
"prefer-destructuring": ["error", { object: true, array: false }],
|
||||||
"import/prefer-default-export": "off",
|
"import/prefer-default-export": "off",
|
||||||
@@ -69,9 +98,9 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ["**/*.test.js"],
|
files: ["**/*.test.ts"],
|
||||||
env: {
|
env: {
|
||||||
jest: true, // now **/*.test.js files' env has both es6 *and* jest
|
jest: true, // now **/*.test.ts files' env has both es6 *and* jest
|
||||||
},
|
},
|
||||||
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
|
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
|
||||||
// "extends": ["plugin:jest/recommended"]
|
// "extends": ["plugin:jest/recommended"]
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
"*.js": "eslint --fix",
|
"*.{js,ts,jsx,tsx}": "eslint --fix",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const devConfig = {
|
|||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.(ts|js)x?$/,
|
||||||
loader: "babel-loader",
|
loader: "babel-loader",
|
||||||
options: babelOptions,
|
options: babelOptions,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const prodConfig = {
|
|||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.(ts|js)x?$/,
|
||||||
loader: "babel-loader",
|
loader: "babel-loader",
|
||||||
options: babelOptions,
|
options: babelOptions,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ module.exports = {
|
|||||||
path: path.resolve("build"),
|
path: path.resolve("build"),
|
||||||
publicPath,
|
publicPath,
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".tsx", "..."],
|
||||||
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+1612
-388
File diff suppressed because it is too large
Load Diff
+37
-7
@@ -8,9 +8,9 @@
|
|||||||
"build": "npm run clean && webpack --config",
|
"build": "npm run clean && webpack --config",
|
||||||
"clean": "rimraf build",
|
"clean": "rimraf build",
|
||||||
"dev": "npm run build -- configuration/webpack/webpack.config.dev.js",
|
"dev": "npm run build -- configuration/webpack/webpack.config.dev.js",
|
||||||
"e2e": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.js",
|
"e2e": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.ts",
|
||||||
"e2e-annotations": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2eAnnotations.test.js",
|
"e2e-annotations": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2eAnnotations.test.ts",
|
||||||
"e2e-prod": "CXG_URL_BASE='https://cellxgene.cziscience.com/d/pbmc3k.cxg/' jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.js",
|
"e2e-prod": "CXG_URL_BASE='https://cellxgene.cziscience.com/d/pbmc3k.cxg/' jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.ts",
|
||||||
"fmt": "eslint --fix src __tests__",
|
"fmt": "eslint --fix src __tests__",
|
||||||
"lint": "eslint --fix src __tests__",
|
"lint": "eslint --fix src __tests__",
|
||||||
"prod": "npm run build -- configuration/webpack/webpack.config.prod.js",
|
"prod": "npm run build -- configuration/webpack/webpack.config.prod.js",
|
||||||
@@ -90,10 +90,38 @@
|
|||||||
"@babel/plugin-transform-runtime": "^7.13.15",
|
"@babel/plugin-transform-runtime": "^7.13.15",
|
||||||
"@babel/preset-env": "^7.13.15",
|
"@babel/preset-env": "^7.13.15",
|
||||||
"@babel/preset-react": "^7.13.13",
|
"@babel/preset-react": "^7.13.13",
|
||||||
|
"@babel/preset-typescript": "^7.14.5",
|
||||||
"@babel/register": "^7.13.16",
|
"@babel/register": "^7.13.16",
|
||||||
"@babel/runtime": "^7.13.16",
|
"@babel/runtime": "^7.13.16",
|
||||||
"@blueprintjs/eslint-plugin": "^0.3.0",
|
"@blueprintjs/eslint-plugin": "^0.3.0",
|
||||||
"@sentry/webpack-plugin": "^1.15.0",
|
"@sentry/webpack-plugin": "^1.15.0",
|
||||||
|
"@types/d3": "^7.0.0",
|
||||||
|
"@types/d3-scale-chromatic": "^3.0.0",
|
||||||
|
"@types/expect-puppeteer": "^4.4.6",
|
||||||
|
"@types/flatbuffers": "^1.10.0",
|
||||||
|
"@types/is-number": "^7.0.1",
|
||||||
|
"@types/jest": "^26.0.24",
|
||||||
|
"@types/jest-environment-puppeteer": "^4.4.1",
|
||||||
|
"@types/lodash.clonedeep": "^4.5.6",
|
||||||
|
"@types/lodash.difference": "^4.5.6",
|
||||||
|
"@types/lodash.every": "^4.6.6",
|
||||||
|
"@types/lodash.filter": "^4.6.6",
|
||||||
|
"@types/lodash.foreach": "^4.5.6",
|
||||||
|
"@types/lodash.isnumber": "^3.0.6",
|
||||||
|
"@types/lodash.map": "^4.6.13",
|
||||||
|
"@types/lodash.pull": "^4.1.6",
|
||||||
|
"@types/lodash.sortby": "^4.7.6",
|
||||||
|
"@types/lodash.uniq": "^4.5.6",
|
||||||
|
"@types/lodash.zip": "^4.2.6",
|
||||||
|
"@types/pako": "^1.0.2",
|
||||||
|
"@types/puppeteer": "^5.4.4",
|
||||||
|
"@types/react": "^17.0.14",
|
||||||
|
"@types/react-dom": "^17.0.9",
|
||||||
|
"@types/react-helmet": "^6.1.2",
|
||||||
|
"@types/react-redux": "^7.1.18",
|
||||||
|
"@types/sha1": "^1.1.3",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
||||||
|
"@typescript-eslint/parser": "^4.28.4",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-jest": "^26.1.0",
|
"babel-jest": "^26.1.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
@@ -106,7 +134,7 @@
|
|||||||
"connect-history-api-fallback": "^1.6.0",
|
"connect-history-api-fallback": "^1.6.0",
|
||||||
"css-loader": "^5.2.4",
|
"css-loader": "^5.2.4",
|
||||||
"eslint": "^7.24.0",
|
"eslint": "^7.24.0",
|
||||||
"eslint-config-airbnb": "^18.2.0",
|
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||||
"eslint-config-prettier": "^8.2.0",
|
"eslint-config-prettier": "^8.2.0",
|
||||||
"eslint-loader": "^4.0.2",
|
"eslint-loader": "^4.0.2",
|
||||||
"eslint-plugin-compat": "^3.8.0",
|
"eslint-plugin-compat": "^3.8.0",
|
||||||
@@ -149,6 +177,7 @@
|
|||||||
"style-loader": "^2.0.0",
|
"style-loader": "^2.0.0",
|
||||||
"sw-precache-webpack-plugin": "^1.0.0",
|
"sw-precache-webpack-plugin": "^1.0.0",
|
||||||
"terser-webpack-plugin": "^5.1.1",
|
"terser-webpack-plugin": "^5.1.1",
|
||||||
|
"typescript": "^4.3.5",
|
||||||
"url-loader": "^4.1.0",
|
"url-loader": "^4.1.0",
|
||||||
"webpack": "^5.34.0",
|
"webpack": "^5.34.0",
|
||||||
"webpack-cli": "^4.6.0",
|
"webpack-cli": "^4.6.0",
|
||||||
@@ -157,10 +186,10 @@
|
|||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"testMatch": [
|
"testMatch": [
|
||||||
"**/__tests__/**/?(*.)(spec|test).js?(x)"
|
"**/__tests__/**/?(*.)(spec|test).ts?(x)"
|
||||||
],
|
],
|
||||||
"setupFiles": [
|
"setupFiles": [
|
||||||
"./__tests__/setupMissingGlobals.js"
|
"./__tests__/setupMissingGlobals.ts"
|
||||||
],
|
],
|
||||||
"coverageDirectory": "./coverage/",
|
"coverageDirectory": "./coverage/",
|
||||||
"collectCoverage": true
|
"collectCoverage": true
|
||||||
@@ -170,7 +199,8 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"presets": [
|
"presets": [
|
||||||
"@babel/preset-env",
|
"@babel/preset-env",
|
||||||
"@babel/preset-react"
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@babel/plugin-proposal-function-bind",
|
"@babel/plugin-proposal-function-bind",
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import { MatrixFBS, AnnotationsHelpers } from "../util/stateManager";
|
|||||||
const { isUserAnnotation } = AnnotationsHelpers;
|
const { isUserAnnotation } = AnnotationsHelpers;
|
||||||
|
|
||||||
export const annotationCreateCategoryAction = (
|
export const annotationCreateCategoryAction = (
|
||||||
newCategoryName,
|
newCategoryName: any,
|
||||||
categoryToDuplicate
|
categoryToDuplicate: any
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
Add a new user-created category to the obs annotations.
|
Add a new user-created category to the obs annotations.
|
||||||
|
|
||||||
@@ -89,9 +89,9 @@ export const annotationCreateCategoryAction = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const annotationRenameCategoryAction = (
|
export const annotationRenameCategoryAction = (
|
||||||
oldCategoryName,
|
oldCategoryName: any,
|
||||||
newCategoryName
|
newCategoryName: any
|
||||||
) => (dispatch, getState) => {
|
) => (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
Rename a user-created annotation category
|
Rename a user-created annotation category
|
||||||
*/
|
*/
|
||||||
@@ -124,9 +124,9 @@ export const annotationRenameCategoryAction = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const annotationDeleteCategoryAction = (categoryName) => (
|
export const annotationDeleteCategoryAction = (categoryName: any) => (
|
||||||
dispatch,
|
dispatch: any,
|
||||||
getState
|
getState: any
|
||||||
) => {
|
) => {
|
||||||
/*
|
/*
|
||||||
Delete a user-created category
|
Delete a user-created category
|
||||||
@@ -149,10 +149,10 @@ export const annotationDeleteCategoryAction = (categoryName) => (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const annotationCreateLabelInCategory = (
|
export const annotationCreateLabelInCategory = (
|
||||||
categoryName,
|
categoryName: any,
|
||||||
labelName,
|
labelName: any,
|
||||||
assignSelected
|
assignSelected: any
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
Add a new label to a user-defined category. If assignSelected is true, assign
|
Add a new label to a user-defined category. If assignSelected is true, assign
|
||||||
the label to all currently selected cells.
|
the label to all currently selected cells.
|
||||||
@@ -188,9 +188,9 @@ export const annotationCreateLabelInCategory = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const annotationDeleteLabelFromCategory = (
|
export const annotationDeleteLabelFromCategory = (
|
||||||
categoryName,
|
categoryName: any,
|
||||||
labelName
|
labelName: any
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
delete a label from a user-defined category
|
delete a label from a user-defined category
|
||||||
*/
|
*/
|
||||||
@@ -218,10 +218,10 @@ export const annotationDeleteLabelFromCategory = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const annotationRenameLabelInCategory = (
|
export const annotationRenameLabelInCategory = (
|
||||||
categoryName,
|
categoryName: any,
|
||||||
oldLabelName,
|
oldLabelName: any,
|
||||||
newLabelName
|
newLabelName: any
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
label name change
|
label name change
|
||||||
*/
|
*/
|
||||||
@@ -255,9 +255,9 @@ export const annotationRenameLabelInCategory = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const annotationLabelCurrentSelection = (
|
export const annotationLabelCurrentSelection = (
|
||||||
categoryName,
|
categoryName: any,
|
||||||
labelName
|
labelName: any
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
set the label on all currently selected
|
set the label on all currently selected
|
||||||
*/
|
*/
|
||||||
@@ -284,13 +284,16 @@ export const annotationLabelCurrentSelection = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function writableAnnotations(annoMatrix) {
|
function writableAnnotations(annoMatrix: any) {
|
||||||
return annoMatrix.schema.annotations.obs.columns
|
return annoMatrix.schema.annotations.obs.columns
|
||||||
.filter((s) => s.writable)
|
.filter((s: any) => s.writable)
|
||||||
.map((s) => s.name);
|
.map((s: any) => s.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const needToSaveObsAnnotations = (annoMatrix, lastSavedAnnoMatrix) => {
|
export const needToSaveObsAnnotations = (
|
||||||
|
annoMatrix: any,
|
||||||
|
lastSavedAnnoMatrix: any
|
||||||
|
) => {
|
||||||
/*
|
/*
|
||||||
Return true if there are LIKELY user-defined annotation modifications between the two
|
Return true if there are LIKELY user-defined annotation modifications between the two
|
||||||
annoMatrices. Technically not an action creator, but intimately intertwined
|
annoMatrices. Technically not an action creator, but intimately intertwined
|
||||||
@@ -314,11 +317,14 @@ export const needToSaveObsAnnotations = (annoMatrix, lastSavedAnnoMatrix) => {
|
|||||||
|
|
||||||
// no schema changes; check for change in contents
|
// no schema changes; check for change in contents
|
||||||
return currentWritable.some(
|
return currentWritable.some(
|
||||||
(col) => annoMatrix.col(col) !== lastSavedAnnoMatrix.col(col)
|
(col: any) => annoMatrix.col(col) !== lastSavedAnnoMatrix.col(col)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveObsAnnotationsAction = () => async (dispatch, getState) => {
|
export const saveObsAnnotationsAction = () => async (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
/*
|
/*
|
||||||
Save the user-created obs annotations IF any have changed.
|
Save the user-created obs annotations IF any have changed.
|
||||||
*/
|
*/
|
||||||
@@ -388,7 +394,10 @@ export const saveObsAnnotationsAction = () => async (dispatch, getState) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveGenesetsAction = () => async (dispatch, getState) => {
|
export const saveGenesetsAction = () => async (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
// bail if gene sets not available, or in readonly mode.
|
// bail if gene sets not available, or in readonly mode.
|
||||||
@@ -465,7 +474,7 @@ export const saveGenesetsAction = () => async (dispatch, getState) => {
|
|||||||
res,
|
res,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.all([
|
return await Promise.all([
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "autosave: genesets complete",
|
type: "autosave: genesets complete",
|
||||||
lastSavedGenesets: genesets,
|
lastSavedGenesets: genesets,
|
||||||
@@ -6,9 +6,9 @@ import { AnnoMatrixObsCrossfilter } from "../annoMatrix";
|
|||||||
import { _setEmbeddingSubset } from "../util/stateManager/viewStackHelpers";
|
import { _setEmbeddingSubset } from "../util/stateManager/viewStackHelpers";
|
||||||
|
|
||||||
export async function _switchEmbedding(
|
export async function _switchEmbedding(
|
||||||
prevAnnoMatrix,
|
prevAnnoMatrix: any,
|
||||||
prevCrossfilter,
|
prevCrossfilter: any,
|
||||||
newEmbeddingName
|
newEmbeddingName: any
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
DRY helper used by embedding action creators
|
DRY helper used by embedding action creators
|
||||||
@@ -25,9 +25,9 @@ export async function _switchEmbedding(
|
|||||||
return [annoMatrix, obsCrossfilter];
|
return [annoMatrix, obsCrossfilter];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const layoutChoiceAction = (newLayoutChoice) => async (
|
export const layoutChoiceAction = (newLayoutChoice: any) => async (
|
||||||
dispatch,
|
dispatch: any,
|
||||||
getState
|
getState: any
|
||||||
) => {
|
) => {
|
||||||
/*
|
/*
|
||||||
On layout choice, make sure we have selected all on the previous layout, AND the new
|
On layout choice, make sure we have selected all on the previous layout, AND the new
|
||||||
@@ -21,7 +21,10 @@ The behavior manifest in these action creators:
|
|||||||
Note that crossfilter indices are lazy created, as needed.
|
Note that crossfilter indices are lazy created, as needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const genesetDelete = (genesetName) => (dispatch, getState) => {
|
export const genesetDelete = (genesetName: any) => (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { genesets } = state;
|
const { genesets } = state;
|
||||||
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
||||||
@@ -40,9 +43,9 @@ export const genesetDelete = (genesetName) => (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const genesetAddGenes = (genesetName, genes) => async (
|
export const genesetAddGenes = (genesetName: any, genes: any) => async (
|
||||||
dispatch,
|
dispatch: any,
|
||||||
getState
|
getState: any
|
||||||
) => {
|
) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { obsCrossfilter: prevObsCrossfilter, annoMatrix } = state;
|
const { obsCrossfilter: prevObsCrossfilter, annoMatrix } = state;
|
||||||
@@ -50,7 +53,7 @@ export const genesetAddGenes = (genesetName, genes) => async (
|
|||||||
const varIndex = schema.annotations.var.index;
|
const varIndex = schema.annotations.var.index;
|
||||||
const df = await annoMatrix.fetch("var", varIndex);
|
const df = await annoMatrix.fetch("var", varIndex);
|
||||||
const geneNames = df.col(varIndex).asArray();
|
const geneNames = df.col(varIndex).asArray();
|
||||||
genes = genes.reduce((acc, gene) => {
|
genes = genes.reduce((acc: any, gene: any) => {
|
||||||
if (geneNames.indexOf(gene.geneSymbol) === -1) {
|
if (geneNames.indexOf(gene.geneSymbol) === -1) {
|
||||||
postUserErrorToast(
|
postUserErrorToast(
|
||||||
`${gene.geneSymbol} doesn't appear to be a valid gene name.`
|
`${gene.geneSymbol} doesn't appear to be a valid gene name.`
|
||||||
@@ -78,9 +81,9 @@ export const genesetAddGenes = (genesetName, genes) => async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const genesetDeleteGenes = (genesetName, geneSymbols) => (
|
export const genesetDeleteGenes = (genesetName: any, geneSymbols: any) => (
|
||||||
dispatch,
|
dispatch: any,
|
||||||
getState
|
getState: any
|
||||||
) => {
|
) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
|
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
|
||||||
@@ -97,7 +100,11 @@ export const genesetDeleteGenes = (genesetName, geneSymbols) => (
|
|||||||
Private
|
Private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function dropGenesetSummaryDimension(obsCrossfilter, state, genesetName) {
|
function dropGenesetSummaryDimension(
|
||||||
|
obsCrossfilter: any,
|
||||||
|
state: any,
|
||||||
|
genesetName: any
|
||||||
|
) {
|
||||||
const { annoMatrix, genesets } = state;
|
const { annoMatrix, genesets } = state;
|
||||||
const varIndex = annoMatrix.schema.annotations?.var?.index;
|
const varIndex = annoMatrix.schema.annotations?.var?.index;
|
||||||
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
||||||
@@ -113,7 +120,7 @@ function dropGenesetSummaryDimension(obsCrossfilter, state, genesetName) {
|
|||||||
return obsCrossfilter.dropDimension("X", query);
|
return obsCrossfilter.dropDimension("X", query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dropGeneDimension(obsCrossfilter, state, gene) {
|
function dropGeneDimension(obsCrossfilter: any, state: any, gene: any) {
|
||||||
const { annoMatrix } = state;
|
const { annoMatrix } = state;
|
||||||
const varIndex = annoMatrix.schema.annotations?.var?.index;
|
const varIndex = annoMatrix.schema.annotations?.var?.index;
|
||||||
const query = {
|
const query = {
|
||||||
@@ -126,10 +133,16 @@ function dropGeneDimension(obsCrossfilter, state, gene) {
|
|||||||
return obsCrossfilter.dropDimension("X", query);
|
return obsCrossfilter.dropDimension("X", query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dropGeneset(dispatch, state, genesetName, geneSymbols) {
|
function dropGeneset(
|
||||||
|
dispatch: any,
|
||||||
|
state: any,
|
||||||
|
genesetName: any,
|
||||||
|
geneSymbols: any
|
||||||
|
) {
|
||||||
const { obsCrossfilter: prevObsCrossfilter } = state;
|
const { obsCrossfilter: prevObsCrossfilter } = state;
|
||||||
const obsCrossfilter = geneSymbols.reduce(
|
const obsCrossfilter = geneSymbols.reduce(
|
||||||
(crossfilter, gene) => dropGeneDimension(crossfilter, state, gene),
|
(crossfilter: any, gene: any) =>
|
||||||
|
dropGeneDimension(crossfilter, state, gene),
|
||||||
dropGenesetSummaryDimension(prevObsCrossfilter, state, genesetName)
|
dropGenesetSummaryDimension(prevObsCrossfilter, state, genesetName)
|
||||||
);
|
);
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -137,7 +150,7 @@ function dropGeneset(dispatch, state, genesetName, geneSymbols) {
|
|||||||
continuousNamespace: { isGeneSetSummary: true },
|
continuousNamespace: { isGeneSetSummary: true },
|
||||||
selection: genesetName,
|
selection: genesetName,
|
||||||
});
|
});
|
||||||
geneSymbols.forEach((g) =>
|
geneSymbols.forEach((g: any) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "continuous metadata histogram cancel",
|
type: "continuous metadata histogram cancel",
|
||||||
continuousNamespace: { isUserDefined: true },
|
continuousNamespace: { isUserDefined: true },
|
||||||
@@ -15,7 +15,7 @@ import * as genesetActions from "./geneset";
|
|||||||
/*
|
/*
|
||||||
return promise fetching user-configured colors
|
return promise fetching user-configured colors
|
||||||
*/
|
*/
|
||||||
async function userColorsFetchAndLoad(dispatch) {
|
async function userColorsFetchAndLoad(dispatch: any) {
|
||||||
return fetchJson("colors").then((response) =>
|
return fetchJson("colors").then((response) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "universe: user color load success",
|
type: "universe: user color load success",
|
||||||
@@ -28,7 +28,7 @@ async function schemaFetch() {
|
|||||||
return fetchJson("schema");
|
return fetchJson("schema");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function configFetch(dispatch) {
|
async function configFetch(dispatch: any) {
|
||||||
return fetchJson("config").then((response) => {
|
return fetchJson("config").then((response) => {
|
||||||
const config = { ...globals.configDefaults, ...response.config };
|
const config = { ...globals.configDefaults, ...response.config };
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -39,7 +39,7 @@ async function configFetch(dispatch) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function userInfoFetch(dispatch) {
|
async function userInfoFetch(dispatch: any) {
|
||||||
return fetchJson("userinfo").then((response) => {
|
return fetchJson("userinfo").then((response) => {
|
||||||
const { userinfo: userInfo } = response || {};
|
const { userinfo: userInfo } = response || {};
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -50,7 +50,7 @@ async function userInfoFetch(dispatch) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function genesetsFetch(dispatch, config) {
|
async function genesetsFetch(dispatch: any, config: any) {
|
||||||
/* request genesets ONLY if the backend supports the feature */
|
/* request genesets ONLY if the backend supports the feature */
|
||||||
const defaultResponse = {
|
const defaultResponse = {
|
||||||
genesets: [],
|
genesets: [],
|
||||||
@@ -71,25 +71,26 @@ async function genesetsFetch(dispatch, config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prefetchEmbeddings(annoMatrix) {
|
function prefetchEmbeddings(annoMatrix: any) {
|
||||||
/*
|
/*
|
||||||
prefetch requests for all embeddings
|
prefetch requests for all embeddings
|
||||||
*/
|
*/
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const available = schema.layout.obs.map((v) => v.name);
|
const available = schema.layout.obs.map((v: any) => v.name);
|
||||||
available.forEach((embName) => annoMatrix.prefetch("emb", embName));
|
available.forEach((embName: any) => annoMatrix.prefetch("emb", embName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Application bootstrap
|
Application bootstrap
|
||||||
*/
|
*/
|
||||||
const doInitialDataLoad = () =>
|
const doInitialDataLoad = () =>
|
||||||
catchErrorsWrap(async (dispatch) => {
|
catchErrorsWrap(async (dispatch: any) => {
|
||||||
dispatch({ type: "initial data load start" });
|
dispatch({ type: "initial data load start" });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [config, schema] = await Promise.all([
|
const [config, schema] = await Promise.all([
|
||||||
configFetch(dispatch),
|
configFetch(dispatch),
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
schemaFetch(dispatch),
|
schemaFetch(dispatch),
|
||||||
userColorsFetchAndLoad(dispatch),
|
userColorsFetchAndLoad(dispatch),
|
||||||
userInfoFetch(dispatch),
|
userInfoFetch(dispatch),
|
||||||
@@ -113,7 +114,7 @@ const doInitialDataLoad = () =>
|
|||||||
const layoutSchema = schema?.schema?.layout?.obs ?? [];
|
const layoutSchema = schema?.schema?.layout?.obs ?? [];
|
||||||
if (
|
if (
|
||||||
defaultEmbedding &&
|
defaultEmbedding &&
|
||||||
layoutSchema.some((s) => s.name === defaultEmbedding)
|
layoutSchema.some((s: any) => s.name === defaultEmbedding)
|
||||||
) {
|
) {
|
||||||
dispatch(embActions.layoutChoiceAction(defaultEmbedding));
|
dispatch(embActions.layoutChoiceAction(defaultEmbedding));
|
||||||
}
|
}
|
||||||
@@ -122,21 +123,22 @@ const doInitialDataLoad = () =>
|
|||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
function requestSingleGeneExpressionCountsForColoringPOST(gene) {
|
function requestSingleGeneExpressionCountsForColoringPOST(gene: any) {
|
||||||
return {
|
return {
|
||||||
type: "color by expression",
|
type: "color by expression",
|
||||||
gene,
|
gene,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestUserDefinedGene = (gene) => ({
|
const requestUserDefinedGene = (gene: any) => ({
|
||||||
type: "request user defined gene success",
|
type: "request user defined gene success",
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
genes: [gene],
|
genes: [gene],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const dispatchDiffExpErrors = (dispatch, response) => {
|
const dispatchDiffExpErrors = (dispatch: any, response: any) => {
|
||||||
switch (response.status) {
|
switch (response.status) {
|
||||||
case 403:
|
case 403:
|
||||||
dispatchNetworkErrorMessageToUser(
|
dispatchNetworkErrorMessageToUser(
|
||||||
@@ -159,10 +161,11 @@ const dispatchDiffExpErrors = (dispatch, response) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const requestDifferentialExpression = (set1, set2, num_genes = 50) => async (
|
const requestDifferentialExpression = (
|
||||||
dispatch,
|
set1: any,
|
||||||
getState
|
set2: any,
|
||||||
) => {
|
num_genes = 50
|
||||||
|
) => async (dispatch: any, getState: any) => {
|
||||||
dispatch({ type: "request differential expression started" });
|
dispatch({ type: "request differential expression started" });
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
@@ -210,7 +213,8 @@ const requestDifferentialExpression = (set1, set2, num_genes = 50) => async (
|
|||||||
const varIndex = await annoMatrix.fetch("var", varIndexName);
|
const varIndex = await annoMatrix.fetch("var", varIndexName);
|
||||||
const diffexpLists = { negative: [], positive: [] };
|
const diffexpLists = { negative: [], positive: [] };
|
||||||
for (const polarity of Object.keys(diffexpLists)) {
|
for (const polarity of Object.keys(diffexpLists)) {
|
||||||
diffexpLists[polarity] = response[polarity].map((v) => [
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
|
diffexpLists[polarity] = response[polarity].map((v: any) => [
|
||||||
varIndex.at(v[0], varIndexName),
|
varIndex.at(v[0], varIndexName),
|
||||||
...v.slice(1),
|
...v.slice(1),
|
||||||
]);
|
]);
|
||||||
@@ -229,7 +233,7 @@ const requestDifferentialExpression = (set1, set2, num_genes = 50) => async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function fetchJson(pathAndQuery) {
|
function fetchJson(pathAndQuery: any) {
|
||||||
return doJsonRequest(
|
return doJsonRequest(
|
||||||
`${globals.API.prefix}${globals.API.version}${pathAndQuery}`
|
`${globals.API.prefix}${globals.API.version}${pathAndQuery}`
|
||||||
);
|
);
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
Action creators for selection
|
Action creators for selection
|
||||||
*/
|
*/
|
||||||
export const selectContinuousMetadataAction = (
|
export const selectContinuousMetadataAction = (
|
||||||
type,
|
type: any,
|
||||||
query,
|
query: any,
|
||||||
range,
|
range: any,
|
||||||
oldProps = {}
|
oldProps = {}
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
||||||
|
|
||||||
const selection = range
|
const selection = range
|
||||||
@@ -29,13 +29,13 @@ export const selectContinuousMetadataAction = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const selectCategoricalMetadataAction = (
|
export const selectCategoricalMetadataAction = (
|
||||||
type, // action type
|
type: any, // action type
|
||||||
metadataField, // annotation category name
|
metadataField: any, // annotation category name
|
||||||
labels,
|
labels: any,
|
||||||
label, // the label being selected/deselected
|
label: any, // the label being selected/deselected
|
||||||
isSelected, // bool
|
isSelected: any, // bool
|
||||||
oldProps = {}
|
oldProps = {}
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
const {
|
const {
|
||||||
obsCrossfilter: prevObsCrossfilter,
|
obsCrossfilter: prevObsCrossfilter,
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
@@ -43,7 +43,7 @@ export const selectCategoricalMetadataAction = (
|
|||||||
|
|
||||||
const labelSelectionState = new Map(categoricalSelection[metadataField]);
|
const labelSelectionState = new Map(categoricalSelection[metadataField]);
|
||||||
labels.forEach(
|
labels.forEach(
|
||||||
(l) => labelSelectionState.has(l) || labelSelectionState.set(l, true)
|
(l: any) => labelSelectionState.has(l) || labelSelectionState.set(l, true)
|
||||||
);
|
);
|
||||||
labelSelectionState.set(label, isSelected);
|
labelSelectionState.set(label, isSelected);
|
||||||
|
|
||||||
@@ -70,19 +70,19 @@ export const selectCategoricalMetadataAction = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const selectCategoricalAllMetadataAction = (
|
export const selectCategoricalAllMetadataAction = (
|
||||||
type, // action type
|
type: any, // action type
|
||||||
metadataField, // annotation category name
|
metadataField: any, // annotation category name
|
||||||
labels,
|
labels: any,
|
||||||
isSelected, // bool, select all or none
|
isSelected: any, // bool, select all or none
|
||||||
oldProps = {}
|
oldProps = {}
|
||||||
) => async (dispatch, getState) => {
|
) => async (dispatch: any, getState: any) => {
|
||||||
const {
|
const {
|
||||||
obsCrossfilter: prevObsCrossfilter,
|
obsCrossfilter: prevObsCrossfilter,
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
} = getState();
|
} = getState();
|
||||||
|
|
||||||
const labelSelectionState = new Map(categoricalSelection[metadataField]);
|
const labelSelectionState = new Map(categoricalSelection[metadataField]);
|
||||||
labels.forEach((label) => labelSelectionState.set(label, isSelected));
|
labels.forEach((label: any) => labelSelectionState.set(label, isSelected));
|
||||||
|
|
||||||
const selection = { mode: isSelected ? "all" : "none" };
|
const selection = { mode: isSelected ? "all" : "none" };
|
||||||
const obsCrossfilter = await prevObsCrossfilter.select(
|
const obsCrossfilter = await prevObsCrossfilter.select(
|
||||||
@@ -108,10 +108,11 @@ export const graphBrushStartAction = () =>
|
|||||||
/* no change to crossfilter until a change fires */
|
/* no change to crossfilter until a change fires */
|
||||||
({ type: "graph brush start" });
|
({ type: "graph brush start" });
|
||||||
|
|
||||||
const _graphBrushWithinRectAction = (type, embName, brushCoords) => async (
|
const _graphBrushWithinRectAction = (
|
||||||
dispatch,
|
type: any,
|
||||||
getState
|
embName: any,
|
||||||
) => {
|
brushCoords: any
|
||||||
|
) => async (dispatch: any, getState: any) => {
|
||||||
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
||||||
|
|
||||||
const selection = { mode: "within-rect", ...brushCoords };
|
const selection = { mode: "within-rect", ...brushCoords };
|
||||||
@@ -128,7 +129,10 @@ const _graphBrushWithinRectAction = (type, embName, brushCoords) => async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const _graphAllAction = (type, embName) => async (dispatch, getState) => {
|
const _graphAllAction = (type: any, embName: any) => async (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
||||||
|
|
||||||
const obsCrossfilter = await prevObsCrossfilter.select("emb", embName, {
|
const obsCrossfilter = await prevObsCrossfilter.select("emb", embName, {
|
||||||
@@ -141,30 +145,30 @@ const _graphAllAction = (type, embName) => async (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const graphBrushChangeAction = (embName, brushCoords) =>
|
export const graphBrushChangeAction = (embName: any, brushCoords: any) =>
|
||||||
_graphBrushWithinRectAction("graph brush change", embName, brushCoords);
|
_graphBrushWithinRectAction("graph brush change", embName, brushCoords);
|
||||||
|
|
||||||
export const graphBrushEndAction = (embName, brushCoords) =>
|
export const graphBrushEndAction = (embName: any, brushCoords: any) =>
|
||||||
_graphBrushWithinRectAction("graph brush end", embName, brushCoords);
|
_graphBrushWithinRectAction("graph brush end", embName, brushCoords);
|
||||||
|
|
||||||
export const graphBrushCancelAction = (embName) =>
|
export const graphBrushCancelAction = (embName: any) =>
|
||||||
_graphAllAction("graph brush cancel", embName);
|
_graphAllAction("graph brush cancel", embName);
|
||||||
export const graphBrushDeselectAction = (embName) =>
|
export const graphBrushDeselectAction = (embName: any) =>
|
||||||
_graphAllAction("graph brush deselect", embName);
|
_graphAllAction("graph brush deselect", embName);
|
||||||
|
|
||||||
export const graphLassoStartAction = () =>
|
export const graphLassoStartAction = () =>
|
||||||
/* no change to crossfilter until a change fires */
|
/* no change to crossfilter until a change fires */
|
||||||
({ type: "graph lasso start" });
|
({ type: "graph lasso start" });
|
||||||
|
|
||||||
export const graphLassoCancelAction = (embName) =>
|
export const graphLassoCancelAction = (embName: any) =>
|
||||||
_graphAllAction("graph lasso cancel", embName);
|
_graphAllAction("graph lasso cancel", embName);
|
||||||
|
|
||||||
export const graphLassoDeselectAction = (embName) =>
|
export const graphLassoDeselectAction = (embName: any) =>
|
||||||
_graphAllAction("graph lasso cancel", embName);
|
_graphAllAction("graph lasso cancel", embName);
|
||||||
|
|
||||||
export const graphLassoEndAction = (embName, polygon) => async (
|
export const graphLassoEndAction = (embName: any, polygon: any) => async (
|
||||||
dispatch,
|
dispatch: any,
|
||||||
getState
|
getState: any
|
||||||
) => {
|
) => {
|
||||||
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
const { obsCrossfilter: prevObsCrossfilter } = getState();
|
||||||
|
|
||||||
@@ -188,7 +192,10 @@ export const graphLassoEndAction = (embName, polygon) => async (
|
|||||||
/*
|
/*
|
||||||
Differential expression set selection
|
Differential expression set selection
|
||||||
*/
|
*/
|
||||||
export const setCellSetFromSelection = (cellSetId) => (dispatch, getState) => {
|
export const setCellSetFromSelection = (cellSetId: any) => (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
const { obsCrossfilter } = getState();
|
const { obsCrossfilter } = getState();
|
||||||
const selected = obsCrossfilter.allSelectedLabels();
|
const selected = obsCrossfilter.allSelectedLabels();
|
||||||
|
|
||||||
@@ -18,7 +18,10 @@ import {
|
|||||||
_userResetSubsetAnnoMatrix,
|
_userResetSubsetAnnoMatrix,
|
||||||
} from "../util/stateManager/viewStackHelpers";
|
} from "../util/stateManager/viewStackHelpers";
|
||||||
|
|
||||||
export const clipAction = (min, max) => (dispatch, getState) => {
|
export const clipAction = (min: any, max: any) => (
|
||||||
|
dispatch: any,
|
||||||
|
getState: any
|
||||||
|
) => {
|
||||||
/*
|
/*
|
||||||
apply a clip to the current annoMatrix. By convention, the clip
|
apply a clip to the current annoMatrix. By convention, the clip
|
||||||
view is ALWAYS the top view.
|
view is ALWAYS the top view.
|
||||||
@@ -34,7 +37,7 @@ export const clipAction = (min, max) => (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const subsetAction = () => (dispatch, getState) => {
|
export const subsetAction = () => (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
Subset the annoMatrix to the current crossfilter selection by pushing a
|
Subset the annoMatrix to the current crossfilter selection by pushing a
|
||||||
subset view.
|
subset view.
|
||||||
@@ -58,7 +61,7 @@ export const subsetAction = () => (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const resetSubsetAction = () => (dispatch, getState) => {
|
export const resetSubsetAction = () => (dispatch: any, getState: any) => {
|
||||||
/*
|
/*
|
||||||
Reset the annoMatrix to all data. Because we may have multiple views
|
Reset the annoMatrix to all data. Because we may have multiple views
|
||||||
stacked, we pop them all. By convention, any clip transformation will
|
stacked, we pop them all. By convention, any clip transformation will
|
||||||
@@ -17,6 +17,28 @@ import { _queryValidate, _queryCacheKey } from "./query";
|
|||||||
const _dataframeCache = dataframeMemo(128);
|
const _dataframeCache = dataframeMemo(128);
|
||||||
|
|
||||||
export default class AnnoMatrix {
|
export default class AnnoMatrix {
|
||||||
|
public isView: any;
|
||||||
|
|
||||||
|
public nObs: any;
|
||||||
|
|
||||||
|
public nVar: any;
|
||||||
|
|
||||||
|
public rowIndex: any;
|
||||||
|
|
||||||
|
public schema: any;
|
||||||
|
|
||||||
|
public userFlags: any;
|
||||||
|
|
||||||
|
public viewOf: any;
|
||||||
|
|
||||||
|
protected _cache: any;
|
||||||
|
|
||||||
|
private _pendingLoad: any;
|
||||||
|
|
||||||
|
private _whereCache: any;
|
||||||
|
|
||||||
|
private _gcInfo: any;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Abstract base class for all AnnoMatrix objects. This class provides a proxy
|
Abstract base class for all AnnoMatrix objects. This class provides a proxy
|
||||||
to the annotated matrix data authoritatively served by the server/back-end.
|
to the annotated matrix data authoritatively served by the server/back-end.
|
||||||
@@ -54,7 +76,7 @@ export default class AnnoMatrix {
|
|||||||
return ["obs", "var", "emb", "X"];
|
return ["obs", "var", "emb", "X"];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(schema, nObs, nVar, rowIndex = null) {
|
constructor(schema: any, nObs: any, nVar: any, rowIndex = null) {
|
||||||
/*
|
/*
|
||||||
Private constructor - this is an abstract base class. Do not use.
|
Private constructor - this is an abstract base class. Do not use.
|
||||||
*/
|
*/
|
||||||
@@ -83,13 +105,13 @@ export default class AnnoMatrix {
|
|||||||
this.userFlags = {};
|
this.userFlags = {};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Private instance variables.
|
Private instance variables.
|
||||||
|
|
||||||
These are caches - lazily loaded. The only guarantee is that if they
|
These are caches - lazily loaded. The only guarantee is that if they
|
||||||
are loaded, they will conform to the schema & dimensionality constraints.
|
are loaded, they will conform to the schema & dimensionality constraints.
|
||||||
|
|
||||||
Do NOT use directly - instead, use the fetch() and preload() API.
|
Do NOT use directly - instead, use the fetch() and preload() API.
|
||||||
*/
|
*/
|
||||||
this._cache = {
|
this._cache = {
|
||||||
obs: Dataframe.empty(this.rowIndex),
|
obs: Dataframe.empty(this.rowIndex),
|
||||||
var: Dataframe.empty(this.rowIndex),
|
var: Dataframe.empty(this.rowIndex),
|
||||||
@@ -109,6 +131,7 @@ export default class AnnoMatrix {
|
|||||||
/**
|
/**
|
||||||
** Schema helper/accessors
|
** Schema helper/accessors
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
getMatrixColumns(field) {
|
getMatrixColumns(field) {
|
||||||
/*
|
/*
|
||||||
Return array of column names in the field. ONLY supported on the
|
Return array of column names in the field. ONLY supported on the
|
||||||
@@ -132,6 +155,7 @@ export default class AnnoMatrix {
|
|||||||
return AnnoMatrix.fields();
|
return AnnoMatrix.fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
getColumnSchema(field, col) {
|
getColumnSchema(field, col) {
|
||||||
/*
|
/*
|
||||||
Return the schema for the field & column ,eg,
|
Return the schema for the field & column ,eg,
|
||||||
@@ -144,6 +168,7 @@ export default class AnnoMatrix {
|
|||||||
return _getColumnSchema(this.schema, field, col);
|
return _getColumnSchema(this.schema, field, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
getColumnDimensions(field, col) {
|
getColumnDimensions(field, col) {
|
||||||
/*
|
/*
|
||||||
Return the dimensions on this field / column. For most fields, which are 1D,
|
Return the dimensions on this field / column. For most fields, which are 1D,
|
||||||
@@ -174,6 +199,7 @@ export default class AnnoMatrix {
|
|||||||
/**
|
/**
|
||||||
** Load / read interfaces
|
** Load / read interfaces
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
fetch(field, q) {
|
fetch(field, q) {
|
||||||
/*
|
/*
|
||||||
Return the given query on a single matrix field as a single dataframe.
|
Return the given query on a single matrix field as a single dataframe.
|
||||||
@@ -231,6 +257,7 @@ export default class AnnoMatrix {
|
|||||||
return this._fetch(field, q);
|
return this._fetch(field, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
prefetch(field, q) {
|
prefetch(field, q) {
|
||||||
/*
|
/*
|
||||||
Start a data fetch & cache fill. Identical to fetch() except it does
|
Start a data fetch & cache fill. Identical to fetch() except it does
|
||||||
@@ -261,7 +288,8 @@ export default class AnnoMatrix {
|
|||||||
** The actual implementation is in the sub-classes, which MUST override these.
|
** The actual implementation is in the sub-classes, which MUST override these.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'col' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
addObsAnnoCategory(col, category) {
|
addObsAnnoCategory(col, category) {
|
||||||
/*
|
/*
|
||||||
Add a new category value (aka "label") to a writable obs column, and return the new AnnoMatrix.
|
Add a new category value (aka "label") to a writable obs column, and return the new AnnoMatrix.
|
||||||
@@ -278,7 +306,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'col' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
||||||
/*
|
/*
|
||||||
Remove a category value from an obs column, reassign any obs having that value
|
Remove a category value from an obs column, reassign any obs having that value
|
||||||
@@ -299,7 +328,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'col' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
dropObsColumn(col) {
|
dropObsColumn(col) {
|
||||||
/*
|
/*
|
||||||
Drop an entire writable column, eg a user-created obs annotation. Typical use
|
Drop an entire writable column, eg a user-created obs annotation. Typical use
|
||||||
@@ -315,7 +345,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'colSchema' is declared but its value is never rea... Remove this comment to see the full error message
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
addObsColumn(colSchema, Ctor, value) {
|
addObsColumn(colSchema, Ctor, value) {
|
||||||
/*
|
/*
|
||||||
Add a new writable OBS annotation column, with the caller-specified schema, initial value
|
Add a new writable OBS annotation column, with the caller-specified schema, initial value
|
||||||
@@ -344,7 +375,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'oldCol' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
renameObsColumn(oldCol, newCol) {
|
renameObsColumn(oldCol, newCol) {
|
||||||
/*
|
/*
|
||||||
Rename the obs column 'oldCol' to have name 'newCol' and returns new AnnoMatrix.
|
Rename the obs column 'oldCol' to have name 'newCol' and returns new AnnoMatrix.
|
||||||
@@ -359,7 +391,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'col' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
async setObsColumnValues(col, obsLabels, value) {
|
async setObsColumnValues(col, obsLabels, value) {
|
||||||
/*
|
/*
|
||||||
Set all obs with label in array 'obsLabels' to have 'value'. Typical use would be
|
Set all obs with label in array 'obsLabels' to have 'value'. Typical use would be
|
||||||
@@ -377,7 +410,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'col' is declared but its value is never read.
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
async resetObsColumnValues(col, oldValue, newValue) {
|
async resetObsColumnValues(col, oldValue, newValue) {
|
||||||
/*
|
/*
|
||||||
Set by value - all elements in the column with value 'oldValue' are set to 'newValue'.
|
Set by value - all elements in the column with value 'oldValue' are set to 'newValue'.
|
||||||
@@ -394,7 +428,8 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars -- make sure subclass implements
|
// @ts-expect-error ts-migrate(6133) FIXME: 'colSchema' is declared but its value is never rea... Remove this comment to see the full error message
|
||||||
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars -- make sure subclass implements
|
||||||
addEmbedding(colSchema) {
|
addEmbedding(colSchema) {
|
||||||
/*
|
/*
|
||||||
Add a new obs embedding to the AnnoMatrix, with provided schema.
|
Add a new obs embedding to the AnnoMatrix, with provided schema.
|
||||||
@@ -407,28 +442,35 @@ export default class AnnoMatrix {
|
|||||||
_subclassResponsibility();
|
_subclassResponsibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
getCacheKeys(field, query) {
|
getCacheKeys(field, query) {
|
||||||
/*
|
/*
|
||||||
Return cache keys for columns associated with this query. May return
|
Return cache keys for columns associated with this query. May return
|
||||||
[unknown] if no keys are known (ie, nothing is or was cached).
|
[unknown] if no keys are known (ie, nothing is or was cached).
|
||||||
*/
|
*/
|
||||||
return _whereCacheGet(this._whereCache, this.schema, field, query);
|
return _whereCacheGet(this._whereCache, this.schema, field, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Private interfaces below.
|
** Private interfaces below.
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_resolveCachedQueries(field, queries) {
|
_resolveCachedQueries(field, queries) {
|
||||||
return queries
|
return (
|
||||||
.map((query) =>
|
queries
|
||||||
_whereCacheGet(this._whereCache, this.schema, field, query).filter(
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'query' implicitly has an 'any' type.
|
||||||
(cacheKey) =>
|
.map((query) =>
|
||||||
cacheKey !== undefined && this._cache[field].hasCol(cacheKey)
|
_whereCacheGet(this._whereCache, this.schema, field, query).filter(
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'cacheKey' implicitly has an 'any' type.
|
||||||
|
(cacheKey) =>
|
||||||
|
cacheKey !== undefined && this._cache[field].hasCol(cacheKey)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.flat()
|
||||||
.flat();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
async _fetch(field, q) {
|
async _fetch(field, q) {
|
||||||
if (!AnnoMatrix.fields().includes(field)) return undefined;
|
if (!AnnoMatrix.fields().includes(field)) return undefined;
|
||||||
const queries = Array.isArray(q) ? q : [q];
|
const queries = Array.isArray(q) ? q : [q];
|
||||||
@@ -441,6 +483,7 @@ export default class AnnoMatrix {
|
|||||||
/* find any query not already cached */
|
/* find any query not already cached */
|
||||||
const uncachedQueries = queries.filter((query) =>
|
const uncachedQueries = queries.filter((query) =>
|
||||||
_whereCacheGet(this._whereCache, this.schema, field, query).some(
|
_whereCacheGet(this._whereCache, this.schema, field, query).some(
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'cacheKey' implicitly has an 'any' type.
|
||||||
(cacheKey) =>
|
(cacheKey) =>
|
||||||
cacheKey === undefined || !this._cache[field].hasCol(cacheKey)
|
cacheKey === undefined || !this._cache[field].hasCol(cacheKey)
|
||||||
)
|
)
|
||||||
@@ -450,8 +493,10 @@ export default class AnnoMatrix {
|
|||||||
if (uncachedQueries.length > 0) {
|
if (uncachedQueries.length > 0) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
uncachedQueries.map((query) =>
|
uncachedQueries.map((query) =>
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter '_field' implicitly has an 'any' type.
|
||||||
this._getPendingLoad(field, query, async (_field, _query) => {
|
this._getPendingLoad(field, query, async (_field, _query) => {
|
||||||
/* fetch, then index. _doLoad is subclass interface */
|
/* fetch, then index. _doLoad is subclass interface */
|
||||||
|
// @ts-expect-error ts-migrate(2488) FIXME: Type 'void' must have a '[Symbol.iterator]()' meth... Remove this comment to see the full error message
|
||||||
const [whereCacheUpdate, df] = await this._doLoad(_field, _query);
|
const [whereCacheUpdate, df] = await this._doLoad(_field, _query);
|
||||||
this._cache[_field] = this._cache[_field].withColsFrom(df);
|
this._cache[_field] = this._cache[_field].withColsFrom(df);
|
||||||
this._whereCache = _whereCacheMerge(
|
this._whereCache = _whereCacheMerge(
|
||||||
@@ -472,6 +517,7 @@ export default class AnnoMatrix {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
async _getPendingLoad(field, query, fetchFn) {
|
async _getPendingLoad(field, query, fetchFn) {
|
||||||
/*
|
/*
|
||||||
Given a query on a field, ensure that we only have a single outstanding
|
Given a query on a field, ensure that we only have a single outstanding
|
||||||
@@ -527,19 +573,21 @@ export default class AnnoMatrix {
|
|||||||
To be effective, the GC callback needs to be invoked from the undo/redo code,
|
To be effective, the GC callback needs to be invoked from the undo/redo code,
|
||||||
as much of the cache is pinned by that data structure.
|
as much of the cache is pinned by that data structure.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_gcField(field, isHot, pinnedColumns) {
|
_gcField(field, isHot, pinnedColumns) {
|
||||||
const maxColumns = isHot ? 256 : 10; // maybe to aggressive?
|
const maxColumns = isHot ? 256 : 10;
|
||||||
|
|
||||||
const cache = this._cache[field];
|
const cache = this._cache[field];
|
||||||
if (cache.colIndex.size() < maxColumns) return; // trivial rejection
|
if (cache.colIndex.size() < maxColumns) return; // trivial rejection
|
||||||
|
|
||||||
const candidates = cache.colIndex
|
const candidates = cache.colIndex
|
||||||
.labels()
|
.labels()
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
.filter((col) => !pinnedColumns.includes(col));
|
.filter((col) => !pinnedColumns.includes(col));
|
||||||
|
|
||||||
const excessCount = candidates.length + pinnedColumns.length - maxColumns;
|
const excessCount = candidates.length + pinnedColumns.length - maxColumns;
|
||||||
if (excessCount > 0) {
|
if (excessCount > 0) {
|
||||||
const { _gcInfo } = this;
|
const { _gcInfo } = this;
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'a' implicitly has an 'any' type.
|
||||||
candidates.sort((a, b) => {
|
candidates.sort((a, b) => {
|
||||||
let atime = _gcInfo.get(_columnCacheKey(field, a));
|
let atime = _gcInfo.get(_columnCacheKey(field, a));
|
||||||
if (atime === undefined) atime = 0;
|
if (atime === undefined) atime = 0;
|
||||||
@@ -558,13 +606,16 @@ export default class AnnoMatrix {
|
|||||||
// )}]`
|
// )}]`
|
||||||
// );
|
// );
|
||||||
this._cache[field] = toDrop.reduce(
|
this._cache[field] = toDrop.reduce(
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'df' implicitly has an 'any' type.
|
||||||
(df, col) => df.dropCol(col),
|
(df, col) => df.dropCol(col),
|
||||||
this._cache[field]
|
this._cache[field]
|
||||||
);
|
);
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
toDrop.forEach((col) => _gcInfo.delete(_columnCacheKey(field, col)));
|
toDrop.forEach((col) => _gcInfo.delete(_columnCacheKey(field, col)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_gcFetchCleanup(field, pinnedColumns) {
|
_gcFetchCleanup(field, pinnedColumns) {
|
||||||
/*
|
/*
|
||||||
Called during data load/fetch. By definition, this is 'hot', so we
|
Called during data load/fetch. By definition, this is 'hot', so we
|
||||||
@@ -579,6 +630,7 @@ export default class AnnoMatrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'hints' implicitly has an 'any' type.
|
||||||
_gc(hints) {
|
_gc(hints) {
|
||||||
/*
|
/*
|
||||||
Called from middleware, or elsewhere. isHot is true if we are in the active store,
|
Called from middleware, or elsewhere. isHot is true if we are in the active store,
|
||||||
@@ -591,6 +643,7 @@ export default class AnnoMatrix {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_gcUpdateStats(field, dataframe) {
|
_gcUpdateStats(field, dataframe) {
|
||||||
/*
|
/*
|
||||||
called each time a query is performed, allowing the gc to update any bookkeeping
|
called each time a query is performed, allowing the gc to update any bookkeeping
|
||||||
@@ -600,6 +653,7 @@ export default class AnnoMatrix {
|
|||||||
const cols = dataframe.colIndex.labels();
|
const cols = dataframe.colIndex.labels();
|
||||||
const { _gcInfo } = this;
|
const { _gcInfo } = this;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'c' implicitly has an 'any' type.
|
||||||
cols.forEach((c) => {
|
cols.forEach((c) => {
|
||||||
_gcInfo.set(_columnCacheKey(field, c), now);
|
_gcInfo.set(_columnCacheKey(field, c), now);
|
||||||
});
|
});
|
||||||
@@ -617,6 +671,7 @@ export default class AnnoMatrix {
|
|||||||
|
|
||||||
Do not override _clone();
|
Do not override _clone();
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'clone' implicitly has an 'any' type.
|
||||||
_cloneDeeper(clone) {
|
_cloneDeeper(clone) {
|
||||||
clone._cache = _shallowClone(this._cache);
|
clone._cache = _shallowClone(this._cache);
|
||||||
clone._gcInfo = new Map();
|
clone._gcInfo = new Map();
|
||||||
@@ -640,6 +695,7 @@ export default class AnnoMatrix {
|
|||||||
/*
|
/*
|
||||||
private utility functions below
|
private utility functions below
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
function _columnCacheKey(field, column) {
|
function _columnCacheKey(field, column) {
|
||||||
return `${field}/${column}`;
|
return `${field}/${column}`;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Shallow clone an object, correctly handling prototype
|
Shallow clone an object, correctly handling prototype
|
||||||
*/
|
*/
|
||||||
export default function _shallowClone(orig) {
|
export default function _shallowClone(orig: any) {
|
||||||
return Object.assign(Object.create(Object.getPrototypeOf(orig)), orig);
|
return Object.assign(Object.create(Object.getPrototypeOf(orig)), orig);
|
||||||
}
|
}
|
||||||
@@ -10,26 +10,31 @@ AnnoMatrix stay in sync:
|
|||||||
import Crossfilter from "../util/typedCrossfilter";
|
import Crossfilter from "../util/typedCrossfilter";
|
||||||
import { _getColumnSchema } from "./schema";
|
import { _getColumnSchema } from "./schema";
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
function _dimensionNameFromDf(field, df) {
|
function _dimensionNameFromDf(field, df) {
|
||||||
const colNames = df.colIndex.labels();
|
const colNames = df.colIndex.labels();
|
||||||
return _dimensionName(field, colNames);
|
return _dimensionName(field, colNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
function _dimensionName(field, colNames) {
|
function _dimensionName(field, colNames) {
|
||||||
if (!Array.isArray(colNames)) return `${field}/${colNames}`;
|
if (!Array.isArray(colNames)) return `${field}/${colNames}`;
|
||||||
return `${field}/${colNames.join(":")}`;
|
return `${field}/${colNames.join(":")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AnnoMatrixObsCrossfilter {
|
export default class AnnoMatrixObsCrossfilter {
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
constructor(annoMatrix, _obsCrossfilter = null) {
|
constructor(annoMatrix, _obsCrossfilter = null) {
|
||||||
this.annoMatrix = annoMatrix;
|
(this as any).annoMatrix = annoMatrix;
|
||||||
this.obsCrossfilter =
|
(this as any).obsCrossfilter =
|
||||||
_obsCrossfilter || new Crossfilter(annoMatrix._cache.obs);
|
_obsCrossfilter || new Crossfilter(annoMatrix._cache.obs);
|
||||||
this.obsCrossfilter = this.obsCrossfilter.setData(annoMatrix._cache.obs);
|
(this as any).obsCrossfilter = (this as any).obsCrossfilter.setData(
|
||||||
|
annoMatrix._cache.obs
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
size() {
|
size() {
|
||||||
return this.obsCrossfilter.size();
|
return (this as any).obsCrossfilter.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,14 +44,23 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
|
|
||||||
See API documentation in annoMatrix.js.
|
See API documentation in annoMatrix.js.
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
addObsColumn(colSchema, Ctor, value) {
|
addObsColumn(colSchema, Ctor, value) {
|
||||||
const annoMatrix = this.annoMatrix.addObsColumn(colSchema, Ctor, value);
|
const annoMatrix = (this as any).annoMatrix.addObsColumn(
|
||||||
const obsCrossfilter = this.obsCrossfilter.setData(annoMatrix._cache.obs);
|
colSchema,
|
||||||
|
Ctor,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
const obsCrossfilter = (this as any).obsCrossfilter.setData(
|
||||||
|
annoMatrix._cache.obs
|
||||||
|
);
|
||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
dropObsColumn(col) {
|
dropObsColumn(col) {
|
||||||
const annoMatrix = this.annoMatrix.dropObsColumn(col);
|
const annoMatrix = (this as any).annoMatrix.dropObsColumn(col);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
const dimName = _dimensionName("obs", col);
|
const dimName = _dimensionName("obs", col);
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
@@ -55,10 +69,12 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'oldCol' implicitly has an 'any' type.
|
||||||
renameObsColumn(oldCol, newCol) {
|
renameObsColumn(oldCol, newCol) {
|
||||||
const annoMatrix = this.annoMatrix.renameObsColumn(oldCol, newCol);
|
const annoMatrix = (this as any).annoMatrix.renameObsColumn(oldCol, newCol);
|
||||||
const oldDimName = _dimensionName("obs", oldCol);
|
const oldDimName = _dimensionName("obs", oldCol);
|
||||||
const newDimName = _dimensionName("obs", newCol);
|
const newDimName = _dimensionName("obs", newCol);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
if (obsCrossfilter.hasDimension(oldDimName)) {
|
if (obsCrossfilter.hasDimension(oldDimName)) {
|
||||||
obsCrossfilter = obsCrossfilter.renameDimension(oldDimName, newDimName);
|
obsCrossfilter = obsCrossfilter.renameDimension(oldDimName, newDimName);
|
||||||
@@ -66,9 +82,14 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
addObsAnnoCategory(col, category) {
|
addObsAnnoCategory(col, category) {
|
||||||
const annoMatrix = this.annoMatrix.addObsAnnoCategory(col, category);
|
const annoMatrix = (this as any).annoMatrix.addObsAnnoCategory(
|
||||||
|
col,
|
||||||
|
category
|
||||||
|
);
|
||||||
const dimName = _dimensionName("obs", col);
|
const dimName = _dimensionName("obs", col);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
||||||
@@ -76,13 +97,15 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
||||||
const annoMatrix = await this.annoMatrix.removeObsAnnoCategory(
|
const annoMatrix = await (this as any).annoMatrix.removeObsAnnoCategory(
|
||||||
col,
|
col,
|
||||||
category,
|
category,
|
||||||
unassignedCategory
|
unassignedCategory
|
||||||
);
|
);
|
||||||
const dimName = _dimensionName("obs", col);
|
const dimName = _dimensionName("obs", col);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
||||||
@@ -90,13 +113,15 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
async setObsColumnValues(col, rowLabels, value) {
|
async setObsColumnValues(col, rowLabels, value) {
|
||||||
const annoMatrix = await this.annoMatrix.setObsColumnValues(
|
const annoMatrix = await (this as any).annoMatrix.setObsColumnValues(
|
||||||
col,
|
col,
|
||||||
rowLabels,
|
rowLabels,
|
||||||
value
|
value
|
||||||
);
|
);
|
||||||
const dimName = _dimensionName("obs", col);
|
const dimName = _dimensionName("obs", col);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
||||||
@@ -104,13 +129,15 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
async resetObsColumnValues(col, oldValue, newValue) {
|
async resetObsColumnValues(col, oldValue, newValue) {
|
||||||
const annoMatrix = await this.annoMatrix.resetObsColumnValues(
|
const annoMatrix = await (this as any).annoMatrix.resetObsColumnValues(
|
||||||
col,
|
col,
|
||||||
oldValue,
|
oldValue,
|
||||||
newValue
|
newValue
|
||||||
);
|
);
|
||||||
const dimName = _dimensionName("obs", col);
|
const dimName = _dimensionName("obs", col);
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
obsCrossfilter = obsCrossfilter.delDimension(dimName);
|
||||||
@@ -118,9 +145,13 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
addEmbedding(colSchema) {
|
addEmbedding(colSchema) {
|
||||||
const annoMatrix = this.annoMatrix.addEmbedding(colSchema);
|
const annoMatrix = (this as any).annoMatrix.addEmbedding(colSchema);
|
||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, this.obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(
|
||||||
|
annoMatrix,
|
||||||
|
(this as any).obsCrossfilter
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,11 +159,15 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
* want to stop trackin the selection state, but aren't sure we want to blow the
|
* want to stop trackin the selection state, but aren't sure we want to blow the
|
||||||
* annomatrix cache.
|
* annomatrix cache.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
dropDimension(field, query) {
|
dropDimension(field, query) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Anno... Remove this comment to see the full error message
|
||||||
const { annoMatrix } = this;
|
const { annoMatrix } = this;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
const keys = annoMatrix
|
const keys = annoMatrix
|
||||||
.getCacheKeys(field, query)
|
.getCacheKeys(field, query)
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'k' implicitly has an 'any' type.
|
||||||
.filter((k) => k !== undefined);
|
.filter((k) => k !== undefined);
|
||||||
const dimName = _dimensionName(field, keys);
|
const dimName = _dimensionName(field, keys);
|
||||||
if (obsCrossfilter.hasDimension(dimName)) {
|
if (obsCrossfilter.hasDimension(dimName)) {
|
||||||
@@ -146,8 +181,11 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
are just wrappers to lazy create indices.
|
are just wrappers to lazy create indices.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
async select(field, query, spec) {
|
async select(field, query, spec) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Anno... Remove this comment to see the full error message
|
||||||
const { annoMatrix } = this;
|
const { annoMatrix } = this;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsCrossfilter' does not exist on type '... Remove this comment to see the full error message
|
||||||
let { obsCrossfilter } = this;
|
let { obsCrossfilter } = this;
|
||||||
|
|
||||||
if (!annoMatrix?._cache?.[field]) {
|
if (!annoMatrix?._cache?.[field]) {
|
||||||
@@ -180,55 +218,59 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
/*
|
/*
|
||||||
Select all on any dimension in this field.
|
Select all on any dimension in this field.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Anno... Remove this comment to see the full error message
|
||||||
const { annoMatrix } = this;
|
const { annoMatrix } = this;
|
||||||
const currentDims = this.obsCrossfilter.dimensionNames();
|
const currentDims = (this as any).obsCrossfilter.dimensionNames();
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'xfltr' implicitly has an 'any' type.
|
||||||
const obsCrossfilter = currentDims.reduce((xfltr, dim) => {
|
const obsCrossfilter = currentDims.reduce((xfltr, dim) => {
|
||||||
return xfltr.select(dim, { mode: "all" });
|
return xfltr.select(dim, { mode: "all" });
|
||||||
}, this.obsCrossfilter);
|
}, (this as any).obsCrossfilter);
|
||||||
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
return new AnnoMatrixObsCrossfilter(annoMatrix, obsCrossfilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
countSelected() {
|
countSelected() {
|
||||||
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
||||||
if (this.obsCrossfilter.size() === 0) return this.annoMatrix.nObs;
|
if ((this as any).obsCrossfilter.size() === 0)
|
||||||
return this.obsCrossfilter.countSelected();
|
return (this as any).annoMatrix.nObs;
|
||||||
|
return (this as any).obsCrossfilter.countSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
allSelectedMask() {
|
allSelectedMask() {
|
||||||
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
||||||
if (
|
if (
|
||||||
this.obsCrossfilter.size() === 0 ||
|
(this as any).obsCrossfilter.size() === 0 ||
|
||||||
this.obsCrossfilter.dimensionNames().length === 0
|
(this as any).obsCrossfilter.dimensionNames().length === 0
|
||||||
) {
|
) {
|
||||||
/* fake the mask */
|
/* fake the mask */
|
||||||
return new Uint8Array(this.annoMatrix.nObs).fill(1);
|
return new Uint8Array((this as any).annoMatrix.nObs).fill(1);
|
||||||
}
|
}
|
||||||
return this.obsCrossfilter.allSelectedMask();
|
return (this as any).obsCrossfilter.allSelectedMask();
|
||||||
}
|
}
|
||||||
|
|
||||||
allSelectedLabels() {
|
allSelectedLabels() {
|
||||||
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
||||||
if (
|
if (
|
||||||
this.obsCrossfilter.size() === 0 ||
|
(this as any).obsCrossfilter.size() === 0 ||
|
||||||
this.obsCrossfilter.dimensionNames().length === 0
|
(this as any).obsCrossfilter.dimensionNames().length === 0
|
||||||
) {
|
) {
|
||||||
return this.annoMatrix.rowIndex.labels();
|
return (this as any).annoMatrix.rowIndex.labels();
|
||||||
}
|
}
|
||||||
|
|
||||||
const mask = this.obsCrossfilter.allSelectedMask();
|
const mask = (this as any).obsCrossfilter.allSelectedMask();
|
||||||
const index = this.annoMatrix.rowIndex.isubsetMask(mask);
|
const index = (this as any).annoMatrix.rowIndex.isubsetMask(mask);
|
||||||
return index.labels();
|
return index.labels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'array' implicitly has an 'any' type.
|
||||||
fillByIsSelected(array, selectedValue, deselectedValue) {
|
fillByIsSelected(array, selectedValue, deselectedValue) {
|
||||||
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
/* if no data yet indexed in the crossfilter, just say everything is selected */
|
||||||
if (
|
if (
|
||||||
this.obsCrossfilter.size() === 0 ||
|
(this as any).obsCrossfilter.size() === 0 ||
|
||||||
this.obsCrossfilter.dimensionNames().length === 0
|
(this as any).obsCrossfilter.dimensionNames().length === 0
|
||||||
) {
|
) {
|
||||||
return array.fill(selectedValue);
|
return array.fill(selectedValue);
|
||||||
}
|
}
|
||||||
return this.obsCrossfilter.fillByIsSelected(
|
return (this as any).obsCrossfilter.fillByIsSelected(
|
||||||
array,
|
array,
|
||||||
selectedValue,
|
selectedValue,
|
||||||
deselectedValue
|
deselectedValue
|
||||||
@@ -239,21 +281,29 @@ export default class AnnoMatrixObsCrossfilter {
|
|||||||
** Private below
|
** Private below
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
_addObsCrossfilterDimension(annoMatrix, obsCrossfilter, field, df) {
|
_addObsCrossfilterDimension(annoMatrix, obsCrossfilter, field, df) {
|
||||||
if (field === "var") return obsCrossfilter;
|
if (field === "var") return obsCrossfilter;
|
||||||
const dimName = _dimensionNameFromDf(field, df);
|
const dimName = _dimensionNameFromDf(field, df);
|
||||||
const dimParams = this._getObsDimensionParams(field, df);
|
const dimParams = this._getObsDimensionParams(field, df);
|
||||||
obsCrossfilter = obsCrossfilter.setData(annoMatrix._cache.obs);
|
obsCrossfilter = obsCrossfilter.setData(annoMatrix._cache.obs);
|
||||||
|
// @ts-expect-error ts-migrate(2488) FIXME: Type 'any[] | undefined' must have a '[Symbol.iter... Remove this comment to see the full error message
|
||||||
obsCrossfilter = obsCrossfilter.addDimension(dimName, ...dimParams);
|
obsCrossfilter = obsCrossfilter.addDimension(dimName, ...dimParams);
|
||||||
return obsCrossfilter;
|
return obsCrossfilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_getColumnBaseType(field, col) {
|
_getColumnBaseType(field, col) {
|
||||||
/* Look up the primitive type for this field/col */
|
/* Look up the primitive type for this field/col */
|
||||||
const colSchema = _getColumnSchema(this.annoMatrix.schema, field, col);
|
const colSchema = _getColumnSchema(
|
||||||
|
(this as any).annoMatrix.schema,
|
||||||
|
field,
|
||||||
|
col
|
||||||
|
);
|
||||||
return colSchema.type;
|
return colSchema.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
_getObsDimensionParams(field, df) {
|
_getObsDimensionParams(field, df) {
|
||||||
/* return the crossfilter dimensiontype type and params for this field/dataframe */
|
/* return the crossfilter dimensiontype type and params for this field/dataframe */
|
||||||
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
export { doBinaryRequest, doFetch } from "../util/actionHelpers";
|
export { doBinaryRequest, doFetch } from "../util/actionHelpers";
|
||||||
|
|
||||||
/* double URI encode - needed for query-param filters */
|
/* double URI encode - needed for query-param filters */
|
||||||
export function _dubEncURIComp(s) {
|
export function _dubEncURIComp(s: any) {
|
||||||
return encodeURIComponent(encodeURIComponent(s));
|
return encodeURIComponent(encodeURIComponent(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* currently unused, consider deleting */
|
/* currently unused, consider deleting */
|
||||||
export function _fetchResult(promise) {
|
export function _fetchResult(promise: any) {
|
||||||
let _status = "pending";
|
let _status = "pending";
|
||||||
const res = promise.then(
|
const res = promise.then(
|
||||||
(r) => {
|
(r: any) => {
|
||||||
_status = "success";
|
_status = "success";
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
(e) => {
|
(e: any) => {
|
||||||
_status = "error";
|
_status = "error";
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
const promiseThrottle = new PromiseLimit(5);
|
const promiseThrottle = new PromiseLimit(5);
|
||||||
|
|
||||||
export default class AnnoMatrixLoader extends AnnoMatrix {
|
export default class AnnoMatrixLoader extends AnnoMatrix {
|
||||||
|
baseURL: any;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AnnoMatrix implementation which proxies to HTTP server using the CXG REST API.
|
AnnoMatrix implementation which proxies to HTTP server using the CXG REST API.
|
||||||
Used as the base (non-view) instance.
|
Used as the base (non-view) instance.
|
||||||
@@ -33,7 +35,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
new AnnoMatrixLoader(serverBaseURL, schema) -> instance
|
new AnnoMatrixLoader(serverBaseURL, schema) -> instance
|
||||||
|
|
||||||
*/
|
*/
|
||||||
constructor(baseURL, schema) {
|
constructor(baseURL: any, schema: any) {
|
||||||
const { nObs, nVar } = schema.dataframe;
|
const { nObs, nVar } = schema.dataframe;
|
||||||
super(schema, nObs, nVar);
|
super(schema, nObs, nVar);
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
/**
|
/**
|
||||||
** Public. API described in base class.
|
** Public. API described in base class.
|
||||||
**/
|
**/
|
||||||
addObsAnnoCategory(col, category) {
|
addObsAnnoCategory(col: any, category: any) {
|
||||||
/*
|
/*
|
||||||
Add a new category (aka label) to the schema for an obs column.
|
Add a new category (aka label) to the schema for an obs column.
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +62,11 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
async removeObsAnnoCategory(
|
||||||
|
col: any,
|
||||||
|
category: any,
|
||||||
|
unassignedCategory: any
|
||||||
|
) {
|
||||||
/*
|
/*
|
||||||
Remove a single "category" (aka "label") from the data & schema of an obs column.
|
Remove a single "category" (aka "label") from the data & schema of an obs column.
|
||||||
*/
|
*/
|
||||||
@@ -80,7 +86,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropObsColumn(col) {
|
dropObsColumn(col: any) {
|
||||||
/*
|
/*
|
||||||
drop column from field
|
drop column from field
|
||||||
*/
|
*/
|
||||||
@@ -88,11 +94,12 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
_writableCheck(colSchema); // throws on error
|
_writableCheck(colSchema); // throws on error
|
||||||
|
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix._cache.obs = this._cache.obs.dropCol(col);
|
newAnnoMatrix._cache.obs = (this as any)._cache.obs.dropCol(col);
|
||||||
newAnnoMatrix.schema = removeObsAnnoColumn(this.schema, col);
|
newAnnoMatrix.schema = removeObsAnnoColumn(this.schema, col);
|
||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
addObsColumn(colSchema, Ctor, value) {
|
addObsColumn(colSchema, Ctor, value) {
|
||||||
/*
|
/*
|
||||||
add a column to field, initializing with value. Value may
|
add a column to field, initializing with value. Value may
|
||||||
@@ -105,7 +112,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
const colName = colSchema.name;
|
const colName = colSchema.name;
|
||||||
if (
|
if (
|
||||||
_getColumnSchema(this.schema, "obs", colName) ||
|
_getColumnSchema(this.schema, "obs", colName) ||
|
||||||
this._cache.obs.hasCol(colName)
|
(this as any)._cache.obs.hasCol(colName)
|
||||||
) {
|
) {
|
||||||
throw new Error("column already exists");
|
throw new Error("column already exists");
|
||||||
}
|
}
|
||||||
@@ -121,7 +128,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
} else {
|
} else {
|
||||||
data = new Ctor(this.nObs).fill(value);
|
data = new Ctor(this.nObs).fill(value);
|
||||||
}
|
}
|
||||||
newAnnoMatrix._cache.obs = this._cache.obs.withCol(colName, data);
|
newAnnoMatrix._cache.obs = (this as any)._cache.obs.withCol(colName, data);
|
||||||
_normalizeCategoricalSchema(
|
_normalizeCategoricalSchema(
|
||||||
colSchema,
|
colSchema,
|
||||||
newAnnoMatrix._cache.obs.col(colName)
|
newAnnoMatrix._cache.obs.col(colName)
|
||||||
@@ -130,15 +137,15 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'oldCol' implicitly has an 'any' type.
|
||||||
renameObsColumn(oldCol, newCol) {
|
renameObsColumn(oldCol, newCol) {
|
||||||
/*
|
/*
|
||||||
Rename the obs oldColName to newColName. oldCol must be writable.
|
Rename the obs oldColName to newColName. oldCol must be writable.
|
||||||
*/
|
*/
|
||||||
const oldColSchema = _getColumnSchema(this.schema, "obs", oldCol);
|
const oldColSchema = _getColumnSchema(this.schema, "obs", oldCol);
|
||||||
_writableCheck(oldColSchema); // throws on error
|
_writableCheck(oldColSchema);
|
||||||
|
const value = (this as any)._cache.obs.hasCol(oldCol)
|
||||||
const value = this._cache.obs.hasCol(oldCol)
|
? (this as any)._cache.obs.col(oldCol).asArray()
|
||||||
? this._cache.obs.col(oldCol).asArray()
|
|
||||||
: undefined;
|
: undefined;
|
||||||
return this.dropObsColumn(oldCol).addObsColumn(
|
return this.dropObsColumn(oldCol).addObsColumn(
|
||||||
{
|
{
|
||||||
@@ -150,6 +157,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
async setObsColumnValues(col, rowLabels, value) {
|
async setObsColumnValues(col, rowLabels, value) {
|
||||||
/*
|
/*
|
||||||
Set all rows identified by rowLabels to value.
|
Set all rows identified by rowLabels to value.
|
||||||
@@ -159,11 +167,11 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
|
|
||||||
// ensure that we have the data in cache before we manipulate it
|
// ensure that we have the data in cache before we manipulate it
|
||||||
await this.fetch("obs", col);
|
await this.fetch("obs", col);
|
||||||
if (!this._cache.obs.hasCol(col))
|
if (!(this as any)._cache.obs.hasCol(col))
|
||||||
throw new Error("Internal error - user annotation data missing");
|
throw new Error("Internal error - user annotation data missing");
|
||||||
|
|
||||||
const rowIndices = this.rowIndex.getOffsets(rowLabels);
|
const rowIndices = this.rowIndex.getOffsets(rowLabels);
|
||||||
const data = this._cache.obs.col(col).asArray().slice();
|
const data = (this as any)._cache.obs.col(col).asArray().slice();
|
||||||
for (let i = 0, len = rowIndices.length; i < len; i += 1) {
|
for (let i = 0, len = rowIndices.length; i < len; i += 1) {
|
||||||
const idx = rowIndices[i];
|
const idx = rowIndices[i];
|
||||||
if (idx === undefined) throw new Error("Unknown row label");
|
if (idx === undefined) throw new Error("Unknown row label");
|
||||||
@@ -171,7 +179,10 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix._cache.obs = this._cache.obs.replaceColData(col, data);
|
newAnnoMatrix._cache.obs = (this as any)._cache.obs.replaceColData(
|
||||||
|
col,
|
||||||
|
data
|
||||||
|
);
|
||||||
const { categories } = colSchema;
|
const { categories } = colSchema;
|
||||||
if (!categories?.includes(value)) {
|
if (!categories?.includes(value)) {
|
||||||
newAnnoMatrix.schema = addObsAnnoCategory(this.schema, col, value);
|
newAnnoMatrix.schema = addObsAnnoCategory(this.schema, col, value);
|
||||||
@@ -179,6 +190,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'col' implicitly has an 'any' type.
|
||||||
async resetObsColumnValues(col, oldValue, newValue) {
|
async resetObsColumnValues(col, oldValue, newValue) {
|
||||||
/*
|
/*
|
||||||
Set all rows with value 'oldValue' to 'newValue'.
|
Set all rows with value 'oldValue' to 'newValue'.
|
||||||
@@ -192,16 +204,19 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
|
|
||||||
// ensure that we have the data in cache before we manipulate it
|
// ensure that we have the data in cache before we manipulate it
|
||||||
await this.fetch("obs", col);
|
await this.fetch("obs", col);
|
||||||
if (!this._cache.obs.hasCol(col))
|
if (!(this as any)._cache.obs.hasCol(col))
|
||||||
throw new Error("Internal error - user annotation data missing");
|
throw new Error("Internal error - user annotation data missing");
|
||||||
|
|
||||||
const data = this._cache.obs.col(col).asArray().slice();
|
const data = (this as any)._cache.obs.col(col).asArray().slice();
|
||||||
for (let i = 0, l = data.length; i < l; i += 1) {
|
for (let i = 0, l = data.length; i < l; i += 1) {
|
||||||
if (data[i] === oldValue) data[i] = newValue;
|
if (data[i] === oldValue) data[i] = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix._cache.obs = this._cache.obs.replaceColData(col, data);
|
newAnnoMatrix._cache.obs = (this as any)._cache.obs.replaceColData(
|
||||||
|
col,
|
||||||
|
data
|
||||||
|
);
|
||||||
const { categories } = colSchema;
|
const { categories } = colSchema;
|
||||||
if (!categories?.includes(newValue)) {
|
if (!categories?.includes(newValue)) {
|
||||||
newAnnoMatrix.schema = addObsAnnoCategory(this.schema, col, newValue);
|
newAnnoMatrix.schema = addObsAnnoCategory(this.schema, col, newValue);
|
||||||
@@ -209,6 +224,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
addEmbedding(colSchema) {
|
addEmbedding(colSchema) {
|
||||||
/*
|
/*
|
||||||
add new layout to the obs embeddings
|
add new layout to the obs embeddings
|
||||||
@@ -226,6 +242,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
/**
|
/**
|
||||||
** Private below
|
** Private below
|
||||||
**/
|
**/
|
||||||
|
// @ts-expect-error ts-migrate(2416) FIXME: Property '_doLoad' in type 'AnnoMatrixLoader' is n... Remove this comment to see the full error message
|
||||||
async _doLoad(field, query) {
|
async _doLoad(field, query) {
|
||||||
/*
|
/*
|
||||||
_doLoad - evaluates the query against the field. Returns:
|
_doLoad - evaluates the query against the field. Returns:
|
||||||
@@ -280,12 +297,14 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
|||||||
Utility functions below
|
Utility functions below
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
function _writableCheck(colSchema) {
|
function _writableCheck(colSchema) {
|
||||||
if (!colSchema?.writable) {
|
if (!colSchema?.writable) {
|
||||||
throw new Error("Unknown or readonly obs column");
|
throw new Error("Unknown or readonly obs column");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
function _writableCategoryTypeCheck(colSchema) {
|
function _writableCategoryTypeCheck(colSchema) {
|
||||||
_writableCheck(colSchema);
|
_writableCheck(colSchema);
|
||||||
if (colSchema.type !== "categorical") {
|
if (colSchema.type !== "categorical") {
|
||||||
@@ -293,6 +312,7 @@ function _writableCategoryTypeCheck(colSchema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'baseURL' implicitly has an 'any' type.
|
||||||
function _embLoader(baseURL, _field, query) {
|
function _embLoader(baseURL, _field, query) {
|
||||||
_expectSimpleQuery(query);
|
_expectSimpleQuery(query);
|
||||||
|
|
||||||
@@ -302,6 +322,7 @@ function _embLoader(baseURL, _field, query) {
|
|||||||
return () => doBinaryRequest(url);
|
return () => doBinaryRequest(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'baseURL' implicitly has an 'any' type.
|
||||||
function _obsOrVarLoader(baseURL, field, query) {
|
function _obsOrVarLoader(baseURL, field, query) {
|
||||||
_expectSimpleQuery(query);
|
_expectSimpleQuery(query);
|
||||||
|
|
||||||
@@ -311,6 +332,7 @@ function _obsOrVarLoader(baseURL, field, query) {
|
|||||||
return () => doBinaryRequest(url);
|
return () => doBinaryRequest(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'baseURL' implicitly has an 'any' type.
|
||||||
function _XLoader(baseURL, field, query) {
|
function _XLoader(baseURL, field, query) {
|
||||||
_expectComplexQuery(query);
|
_expectComplexQuery(query);
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ Undoable metareducer and the AnnoMatrix private API. It would be helpful
|
|||||||
to make the Undoable interface better factored.
|
to make the Undoable interface better factored.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const annoMatrixGC = (store) => (next) => (action) => {
|
const annoMatrixGC = (store: any) => (next: any) => (action: any) => {
|
||||||
if (_itIsTimeForGC()) {
|
if (_itIsTimeForGC()) {
|
||||||
_doGC(store);
|
_doGC(store);
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ function _itIsTimeForGC() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _doGC(store) {
|
function _doGC(store: any) {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
|
|
||||||
// these should probably be a function imported from undoable.js, etc, as
|
// these should probably be a function imported from undoable.js, etc, as
|
||||||
@@ -43,8 +43,8 @@ function _doGC(store) {
|
|||||||
const undoableFuture = state["@@undoable/future"];
|
const undoableFuture = state["@@undoable/future"];
|
||||||
const undoableStack = undoablePast
|
const undoableStack = undoablePast
|
||||||
.concat(undoableFuture)
|
.concat(undoableFuture)
|
||||||
.flatMap((snapshot) =>
|
.flatMap((snapshot: any) =>
|
||||||
snapshot.filter((v) => v[0] === "annoMatrix").map((v) => v[1])
|
snapshot.filter((v: any) => v[0] === "annoMatrix").map((v: any) => v[1])
|
||||||
);
|
);
|
||||||
const currentAnnoMatrix = state.annoMatrix;
|
const currentAnnoMatrix = state.annoMatrix;
|
||||||
|
|
||||||
@@ -53,14 +53,16 @@ function _doGC(store) {
|
|||||||
as our current gc algo is more aggressive with those not hot.
|
as our current gc algo is more aggressive with those not hot.
|
||||||
*/
|
*/
|
||||||
const allAnnoMatrices = new Map(
|
const allAnnoMatrices = new Map(
|
||||||
undoableStack.map((m) => [m, { isHot: false }])
|
undoableStack.map((m: any) => [m, { isHot: false }])
|
||||||
);
|
);
|
||||||
let am = currentAnnoMatrix;
|
let am = currentAnnoMatrix;
|
||||||
while (am) {
|
while (am) {
|
||||||
allAnnoMatrices.set(am, { isHot: true });
|
allAnnoMatrices.set(am, { isHot: true });
|
||||||
am = am.viewOf;
|
am = am.viewOf;
|
||||||
}
|
}
|
||||||
allAnnoMatrices.forEach((hints, annoMatrix) => annoMatrix._gc(hints));
|
allAnnoMatrices.forEach((hints, annoMatrix) =>
|
||||||
|
(annoMatrix as any)._gc(hints)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default annoMatrixGC;
|
export default annoMatrixGC;
|
||||||
@@ -10,7 +10,7 @@ import { _dubEncURIComp } from "./fetchHelpers";
|
|||||||
* @param {object | string} query - the query
|
* @param {object | string} query - the query
|
||||||
* @returns {object | string} - the normalized query
|
* @returns {object | string} - the normalized query
|
||||||
*/
|
*/
|
||||||
export function _queryValidate(query) {
|
export function _queryValidate(query: any) {
|
||||||
if (typeof query !== "object") return query;
|
if (typeof query !== "object") return query;
|
||||||
|
|
||||||
if (query.where && query.summarize)
|
if (query.where && query.summarize)
|
||||||
@@ -40,11 +40,11 @@ export function _queryValidate(query) {
|
|||||||
throw new Error("query must specify one of where or summarize");
|
throw new Error("query must specify one of where or summarize");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _expectSimpleQuery(query) {
|
export function _expectSimpleQuery(query: any) {
|
||||||
if (typeof query === "object") throw new Error("expected simple query");
|
if (typeof query === "object") throw new Error("expected simple query");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _expectComplexQuery(query) {
|
export function _expectComplexQuery(query: any) {
|
||||||
if (typeof query !== "object") throw new Error("expected complex query");
|
if (typeof query !== "object") throw new Error("expected complex query");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ export function _expectComplexQuery(query) {
|
|||||||
* @param {string|object} query
|
* @param {string|object} query
|
||||||
* @returns the key
|
* @returns the key
|
||||||
*/
|
*/
|
||||||
export function _queryCacheKey(field, query) {
|
export function _queryCacheKey(field: any, query: any) {
|
||||||
if (typeof query === "object") {
|
if (typeof query === "object") {
|
||||||
// complex query
|
// complex query
|
||||||
if (query.where) {
|
if (query.where) {
|
||||||
@@ -84,22 +84,22 @@ export function _queryCacheKey(field, query) {
|
|||||||
return `${field}/${query}`;
|
return `${field}/${query}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _urlEncodeWhereQuery(q) {
|
function _urlEncodeWhereQuery(q: any) {
|
||||||
const { field: queryField, column: queryColumn, value: queryValue } = q;
|
const { field: queryField, column: queryColumn, value: queryValue } = q;
|
||||||
return `${_dubEncURIComp(queryField)}:${_dubEncURIComp(
|
return `${_dubEncURIComp(queryField)}:${_dubEncURIComp(
|
||||||
queryColumn
|
queryColumn
|
||||||
)}=${_dubEncURIComp(queryValue)}`;
|
)}=${_dubEncURIComp(queryValue)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _urlEncodeSummarizeQuery(q) {
|
function _urlEncodeSummarizeQuery(q: any) {
|
||||||
const { method, field, column, values } = q;
|
const { method, field, column, values } = q;
|
||||||
const filter = values
|
const filter = values
|
||||||
.map((value) => _urlEncodeWhereQuery({ field, column, value }))
|
.map((value: any) => _urlEncodeWhereQuery({ field, column, value }))
|
||||||
.join("&");
|
.join("&");
|
||||||
return `method=${method}&${filter}`;
|
return `method=${method}&${filter}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _urlEncodeComplexQuery(q) {
|
export function _urlEncodeComplexQuery(q: any) {
|
||||||
if (typeof q === "object") {
|
if (typeof q === "object") {
|
||||||
if (q.where) {
|
if (q.where) {
|
||||||
return _urlEncodeWhereQuery(q.where);
|
return _urlEncodeWhereQuery(q.where);
|
||||||
@@ -111,7 +111,7 @@ export function _urlEncodeComplexQuery(q) {
|
|||||||
throw new Error("Unrecognized complex query type");
|
throw new Error("Unrecognized complex query type");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _urlEncodeLabelQuery(colKey, q) {
|
export function _urlEncodeLabelQuery(colKey: any, q: any) {
|
||||||
if (!colKey) throw new Error("Unsupported query by name");
|
if (!colKey) throw new Error("Unsupported query by name");
|
||||||
if (typeof q !== "string") throw new Error("Query must be a simple label.");
|
if (typeof q !== "string") throw new Error("Query must be a simple label.");
|
||||||
return `${colKey}=${encodeURIComponent(q)}`;
|
return `${colKey}=${encodeURIComponent(q)}`;
|
||||||
@@ -120,7 +120,7 @@ export function _urlEncodeLabelQuery(colKey, q) {
|
|||||||
/**
|
/**
|
||||||
* Generate the column key the server will send us for this query.
|
* Generate the column key the server will send us for this query.
|
||||||
*/
|
*/
|
||||||
export function _hashStringValues(arrayOfString) {
|
export function _hashStringValues(arrayOfString: any) {
|
||||||
const hash = sha1(arrayOfString.join(""));
|
const hash = sha1(arrayOfString.join(""));
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ Private helper functions related to schema
|
|||||||
import catLabelSort from "../util/catLabelSort";
|
import catLabelSort from "../util/catLabelSort";
|
||||||
import { unassignedCategoryLabel } from "../globals";
|
import { unassignedCategoryLabel } from "../globals";
|
||||||
|
|
||||||
export function _getColumnSchema(schema, field, col) {
|
export function _getColumnSchema(schema: any, field: any, col: any) {
|
||||||
/* look up the column definition */
|
/* look up the column definition */
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case "obs":
|
case "obs":
|
||||||
@@ -26,7 +26,7 @@ export function _getColumnSchema(schema, field, col) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _getColumnDimensionNames(schema, field, col) {
|
export function _getColumnDimensionNames(schema: any, field: any, col: any) {
|
||||||
/*
|
/*
|
||||||
field/col may be an alias for multiple columns. Currently used to map ND
|
field/col may be an alias for multiple columns. Currently used to map ND
|
||||||
values to 1D dataframe columns for embeddings/layout. Signified by the presence
|
values to 1D dataframe columns for embeddings/layout. Signified by the presence
|
||||||
@@ -39,6 +39,7 @@ export function _getColumnDimensionNames(schema, field, col) {
|
|||||||
return colSchema.dims || [col];
|
return colSchema.dims || [col];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'schema' implicitly has an 'any' type.
|
||||||
export function _schemaColumns(schema, field) {
|
export function _schemaColumns(schema, field) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case "obs":
|
case "obs":
|
||||||
@@ -52,18 +53,25 @@ export function _schemaColumns(schema, field) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'schema' implicitly has an 'any' type.
|
||||||
export function _getWritableColumns(schema, field) {
|
export function _getWritableColumns(schema, field) {
|
||||||
if (field !== "obs") return [];
|
if (field !== "obs") return [];
|
||||||
return schema.annotations.obs.columns
|
return (
|
||||||
.filter((v) => v.writable)
|
schema.annotations.obs.columns
|
||||||
.map((v) => v.name);
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'v' implicitly has an 'any' type.
|
||||||
|
.filter((v) => v.writable)
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'v' implicitly has an 'any' type.
|
||||||
|
.map((v) => v.name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'schema' implicitly has an 'any' type.
|
||||||
export function _isContinuousType(schema) {
|
export function _isContinuousType(schema) {
|
||||||
const { type } = schema;
|
const { type } = schema;
|
||||||
return !(type === "string" || type === "boolean" || type === "categorical");
|
return !(type === "string" || type === "boolean" || type === "categorical");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colSchema' implicitly has an 'any' type... Remove this comment to see the full error message
|
||||||
export function _normalizeCategoricalSchema(colSchema, col) {
|
export function _normalizeCategoricalSchema(colSchema, col) {
|
||||||
const { type, writable } = colSchema;
|
const { type, writable } = colSchema;
|
||||||
if (
|
if (
|
||||||
@@ -5,7 +5,7 @@ instances of AnnoMatrix, implementing common UI functions.
|
|||||||
|
|
||||||
import { AnnoMatrixRowSubsetView, AnnoMatrixClipView } from "./views";
|
import { AnnoMatrixRowSubsetView, AnnoMatrixClipView } from "./views";
|
||||||
|
|
||||||
export function isubsetMask(annoMatrix, obsMask) {
|
export function isubsetMask(annoMatrix: any, obsMask: any) {
|
||||||
/*
|
/*
|
||||||
Subset annomatrix to contain the rows which have truish value in the mask.
|
Subset annomatrix to contain the rows which have truish value in the mask.
|
||||||
Maks length must equal annoMatrix.nObs (row count).
|
Maks length must equal annoMatrix.nObs (row count).
|
||||||
@@ -13,6 +13,7 @@ export function isubsetMask(annoMatrix, obsMask) {
|
|||||||
return isubset(annoMatrix, _maskToList(obsMask));
|
return isubset(annoMatrix, _maskToList(obsMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
export function isubset(annoMatrix, obsOffsets) {
|
export function isubset(annoMatrix, obsOffsets) {
|
||||||
/*
|
/*
|
||||||
Subset annomatrix to contain the positions contained in the obsOffsets array
|
Subset annomatrix to contain the positions contained in the obsOffsets array
|
||||||
@@ -25,6 +26,7 @@ export function isubset(annoMatrix, obsOffsets) {
|
|||||||
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
export function subset(annoMatrix, obsLabels) {
|
export function subset(annoMatrix, obsLabels) {
|
||||||
/*
|
/*
|
||||||
subset based on labels
|
subset based on labels
|
||||||
@@ -33,6 +35,7 @@ export function subset(annoMatrix, obsLabels) {
|
|||||||
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
export function subsetByIndex(annoMatrix, obsIndex) {
|
export function subsetByIndex(annoMatrix, obsIndex) {
|
||||||
/*
|
/*
|
||||||
subset based upon the new obs index.
|
subset based upon the new obs index.
|
||||||
@@ -40,6 +43,7 @@ export function subsetByIndex(annoMatrix, obsIndex) {
|
|||||||
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
return new AnnoMatrixRowSubsetView(annoMatrix, obsIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||||
export function clip(annoMatrix, qmin, qmax) {
|
export function clip(annoMatrix, qmin, qmax) {
|
||||||
/*
|
/*
|
||||||
Create a view that clips all continuous data to the [min, max] range.
|
Create a view that clips all continuous data to the [min, max] range.
|
||||||
@@ -53,6 +57,7 @@ export function clip(annoMatrix, qmin, qmax) {
|
|||||||
Private utility functions below
|
Private utility functions below
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'mask' implicitly has an 'any' type.
|
||||||
function _maskToList(mask) {
|
function _maskToList(mask) {
|
||||||
/* convert masks to lists - method wastes space, but is fast */
|
/* convert masks to lists - method wastes space, but is fast */
|
||||||
if (!mask) {
|
if (!mask) {
|
||||||
@@ -9,21 +9,26 @@ import { _whereCacheCreate } from "./whereCache";
|
|||||||
import { _isContinuousType, _getColumnSchema } from "./schema";
|
import { _isContinuousType, _getColumnSchema } from "./schema";
|
||||||
|
|
||||||
class AnnoMatrixView extends AnnoMatrix {
|
class AnnoMatrixView extends AnnoMatrix {
|
||||||
constructor(viewOf, rowIndex = null) {
|
constructor(viewOf: any, rowIndex = null) {
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const nObs = rowIndex ? rowIndex.size() : viewOf.nObs;
|
const nObs = rowIndex ? rowIndex.size() : viewOf.nObs;
|
||||||
super(viewOf.schema, nObs, viewOf.nVar, rowIndex || viewOf.rowIndex);
|
super(viewOf.schema, nObs, viewOf.nVar, rowIndex || viewOf.rowIndex);
|
||||||
this.viewOf = viewOf;
|
this.viewOf = viewOf;
|
||||||
this.isView = true;
|
this.isView = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
addObsAnnoCategory(col, category) {
|
addObsAnnoCategory(col: any, category: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = this.viewOf.addObsAnnoCategory(col, category);
|
newAnnoMatrix.viewOf = this.viewOf.addObsAnnoCategory(col, category);
|
||||||
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeObsAnnoCategory(col, category, unassignedCategory) {
|
async removeObsAnnoCategory(
|
||||||
|
col: any,
|
||||||
|
category: any,
|
||||||
|
unassignedCategory: any
|
||||||
|
) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = await this.viewOf.removeObsAnnoCategory(
|
newAnnoMatrix.viewOf = await this.viewOf.removeObsAnnoCategory(
|
||||||
col,
|
col,
|
||||||
@@ -34,7 +39,7 @@ class AnnoMatrixView extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropObsColumn(col) {
|
dropObsColumn(col: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = this.viewOf.dropObsColumn(col);
|
newAnnoMatrix.viewOf = this.viewOf.dropObsColumn(col);
|
||||||
newAnnoMatrix._cache.obs = this._cache.obs.dropCol(col);
|
newAnnoMatrix._cache.obs = this._cache.obs.dropCol(col);
|
||||||
@@ -42,21 +47,21 @@ class AnnoMatrixView extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
addObsColumn(colSchema, Ctor, value) {
|
addObsColumn(colSchema: any, Ctor: any, value: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = this.viewOf.addObsColumn(colSchema, Ctor, value);
|
newAnnoMatrix.viewOf = this.viewOf.addObsColumn(colSchema, Ctor, value);
|
||||||
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
renameObsColumn(oldCol, newCol) {
|
renameObsColumn(oldCol: any, newCol: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = this.viewOf.renameObsColumn(oldCol, newCol);
|
newAnnoMatrix.viewOf = this.viewOf.renameObsColumn(oldCol, newCol);
|
||||||
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setObsColumnValues(col, rowLabels, value) {
|
async setObsColumnValues(col: any, rowLabels: any, value: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = await this.viewOf.setObsColumnValues(
|
newAnnoMatrix.viewOf = await this.viewOf.setObsColumnValues(
|
||||||
col,
|
col,
|
||||||
@@ -68,7 +73,7 @@ class AnnoMatrixView extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetObsColumnValues(col, oldValue, newValue) {
|
async resetObsColumnValues(col: any, oldValue: any, newValue: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = await this.viewOf.resetObsColumnValues(
|
newAnnoMatrix.viewOf = await this.viewOf.resetObsColumnValues(
|
||||||
col,
|
col,
|
||||||
@@ -80,7 +85,7 @@ class AnnoMatrixView extends AnnoMatrix {
|
|||||||
return newAnnoMatrix;
|
return newAnnoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
addEmbedding(colSchema) {
|
addEmbedding(colSchema: any) {
|
||||||
const newAnnoMatrix = this._clone();
|
const newAnnoMatrix = this._clone();
|
||||||
newAnnoMatrix.viewOf = this.viewOf.addEmbedding(colSchema);
|
newAnnoMatrix.viewOf = this.viewOf.addEmbedding(colSchema);
|
||||||
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
newAnnoMatrix.schema = newAnnoMatrix.viewOf.schema;
|
||||||
@@ -92,17 +97,20 @@ class AnnoMatrixMapView extends AnnoMatrixView {
|
|||||||
/*
|
/*
|
||||||
A view which knows how to transform its data.
|
A view which knows how to transform its data.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'viewOf' implicitly has an 'any' type.
|
||||||
constructor(viewOf, mapFn) {
|
constructor(viewOf, mapFn) {
|
||||||
super(viewOf);
|
super(viewOf);
|
||||||
this.mapFn = mapFn;
|
(this as any).mapFn = mapFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2416) FIXME: Property '_doLoad' in type 'AnnoMatrixMapView' is ... Remove this comment to see the full error message
|
||||||
async _doLoad(field, query) {
|
async _doLoad(field, query) {
|
||||||
const df = await this.viewOf._fetch(field, query);
|
const df = await this.viewOf._fetch(field, query);
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'colData' implicitly has an 'any' type.
|
||||||
const dfMapped = df.mapColumns((colData, colIdx) => {
|
const dfMapped = df.mapColumns((colData, colIdx) => {
|
||||||
const colLabel = df.colIndex.getLabel(colIdx);
|
const colLabel = df.colIndex.getLabel(colIdx);
|
||||||
const colSchema = _getColumnSchema(this.schema, field, colLabel);
|
const colSchema = _getColumnSchema(this.schema, field, colLabel);
|
||||||
return this.mapFn(field, colLabel, colSchema, colData, df);
|
return (this as any).mapFn(field, colLabel, colSchema, colData, df);
|
||||||
});
|
});
|
||||||
const whereCacheUpdate = _whereCacheCreate(
|
const whereCacheUpdate = _whereCacheCreate(
|
||||||
field,
|
field,
|
||||||
@@ -117,12 +125,14 @@ export class AnnoMatrixClipView extends AnnoMatrixMapView {
|
|||||||
/*
|
/*
|
||||||
A view which is a clipped transformation of its parent
|
A view which is a clipped transformation of its parent
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'viewOf' implicitly has an 'any' type.
|
||||||
constructor(viewOf, qmin, qmax) {
|
constructor(viewOf, qmin, qmax) {
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
super(viewOf, (field, colLabel, colSchema, colData, df) =>
|
super(viewOf, (field, colLabel, colSchema, colData, df) =>
|
||||||
_clipAnnoMatrix(field, colLabel, colSchema, colData, df, qmin, qmax)
|
_clipAnnoMatrix(field, colLabel, colSchema, colData, df, qmin, qmax)
|
||||||
);
|
);
|
||||||
this.isClipped = true;
|
(this as any).isClipped = true;
|
||||||
this.clipRange = [qmin, qmax];
|
(this as any).clipRange = [qmin, qmax];
|
||||||
Object.seal(this);
|
Object.seal(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,11 +141,13 @@ export class AnnoMatrixRowSubsetView extends AnnoMatrixView {
|
|||||||
/*
|
/*
|
||||||
A view which is a subset of total rows.
|
A view which is a subset of total rows.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'viewOf' implicitly has an 'any' type.
|
||||||
constructor(viewOf, rowIndex) {
|
constructor(viewOf, rowIndex) {
|
||||||
super(viewOf, rowIndex);
|
super(viewOf, rowIndex);
|
||||||
Object.seal(this);
|
Object.seal(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2416) FIXME: Property '_doLoad' in type 'AnnoMatrixRowSubsetVie... Remove this comment to see the full error message
|
||||||
async _doLoad(field, query) {
|
async _doLoad(field, query) {
|
||||||
const df = await this.viewOf._fetch(field, query);
|
const df = await this.viewOf._fetch(field, query);
|
||||||
|
|
||||||
@@ -158,6 +170,7 @@ export class AnnoMatrixRowSubsetView extends AnnoMatrixView {
|
|||||||
Utility functions below
|
Utility functions below
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
function _clipAnnoMatrix(field, colLabel, colSchema, colData, df, qmin, qmax) {
|
function _clipAnnoMatrix(field, colLabel, colSchema, colData, df, qmin, qmax) {
|
||||||
/* only clip obs and var scalar columns */
|
/* only clip obs and var scalar columns */
|
||||||
if (field !== "obs" && field !== "X") return colData;
|
if (field !== "obs" && field !== "X") return colData;
|
||||||
@@ -51,7 +51,12 @@ creates a cache entry of:
|
|||||||
import { _getColumnDimensionNames } from "./schema";
|
import { _getColumnDimensionNames } from "./schema";
|
||||||
import { _hashStringValues } from "./query";
|
import { _hashStringValues } from "./query";
|
||||||
|
|
||||||
export function _whereCacheGet(whereCache, schema, field, query) {
|
export function _whereCacheGet(
|
||||||
|
whereCache: any,
|
||||||
|
schema: any,
|
||||||
|
field: any,
|
||||||
|
query: any
|
||||||
|
) {
|
||||||
/*
|
/*
|
||||||
query will either be an where query (object) or a column name (string).
|
query will either be an where query (object) or a column name (string).
|
||||||
|
|
||||||
@@ -85,6 +90,7 @@ export function _whereCacheGet(whereCache, schema, field, query) {
|
|||||||
return _getColumnDimensionNames(schema, field, query) ?? [undefined];
|
return _getColumnDimensionNames(schema, field, query) ?? [undefined];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||||
export function _whereCacheCreate(field, query, columnLabels) {
|
export function _whereCacheCreate(field, query, columnLabels) {
|
||||||
/*
|
/*
|
||||||
Create a new whereCache
|
Create a new whereCache
|
||||||
@@ -131,10 +137,11 @@ export function _whereCacheCreate(field, query, columnLabels) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'dst' implicitly has an 'any' type.
|
||||||
function __mergeQueries(dst, src) {
|
function __mergeQueries(dst, src) {
|
||||||
for (const [queryField, columnMap] of Object.entries(src)) {
|
for (const [queryField, columnMap] of Object.entries(src)) {
|
||||||
dst[queryField] = dst[queryField] || new Map();
|
dst[queryField] = dst[queryField] || new Map();
|
||||||
for (const [queryColumn, valueMap] of columnMap) {
|
for (const [queryColumn, valueMap] of columnMap as any) {
|
||||||
if (!dst[queryField].has(queryColumn))
|
if (!dst[queryField].has(queryColumn))
|
||||||
dst[queryField].set(queryColumn, new Map());
|
dst[queryField].set(queryColumn, new Map());
|
||||||
for (const [queryValue, columnLabels] of valueMap) {
|
for (const [queryValue, columnLabels] of valueMap) {
|
||||||
@@ -144,6 +151,7 @@ function __mergeQueries(dst, src) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'dst' implicitly has an 'any' type.
|
||||||
function __whereCacheMerge(dst, src) {
|
function __whereCacheMerge(dst, src) {
|
||||||
/*
|
/*
|
||||||
merge src into dst (modifies dst)
|
merge src into dst (modifies dst)
|
||||||
@@ -161,6 +169,7 @@ function __whereCacheMerge(dst, src) {
|
|||||||
dst.summarize = dst.summarize || {};
|
dst.summarize = dst.summarize || {};
|
||||||
for (const [field, method] of Object.entries(src.summarize)) {
|
for (const [field, method] of Object.entries(src.summarize)) {
|
||||||
dst.summarize[field] = dst.summarize[field] || {};
|
dst.summarize[field] = dst.summarize[field] || {};
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
for (const [methodName, query] of Object.entries(method)) {
|
for (const [methodName, query] of Object.entries(method)) {
|
||||||
dst.summarize[field][methodName] =
|
dst.summarize[field][methodName] =
|
||||||
dst.summarize[field][methodName] || {};
|
dst.summarize[field][methodName] || {};
|
||||||
@@ -171,6 +180,7 @@ function __whereCacheMerge(dst, src) {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(7019) FIXME: Rest parameter 'caches' implicitly has an 'any[]' ... Remove this comment to see the full error message
|
||||||
export function _whereCacheMerge(...caches) {
|
export function _whereCacheMerge(...caches) {
|
||||||
return caches.reduce(__whereCacheMerge, {});
|
return caches.reduce(__whereCacheMerge, {});
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,49 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, Tooltip, Dialog, Classes, Colors } from "@blueprintjs/core";
|
import { Button, Tooltip, Dialog, Classes, Colors } from "@blueprintjs/core";
|
||||||
|
|
||||||
class AnnoDialog extends React.PureComponent {
|
type State = any;
|
||||||
constructor(props) {
|
|
||||||
|
class AnnoDialog extends React.PureComponent<{}, State> {
|
||||||
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isActive' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
isActive,
|
isActive,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'text' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||||
text,
|
text,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'title' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
title,
|
title,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'instruction' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
instruction,
|
instruction,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'cancelTooltipContent' does not exist on ... Remove this comment to see the full error message
|
||||||
cancelTooltipContent,
|
cancelTooltipContent,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'errorMessage' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'validationError' does not exist on type ... Remove this comment to see the full error message
|
||||||
validationError,
|
validationError,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoSelect' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
annoSelect,
|
annoSelect,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoInput' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
annoInput,
|
annoInput,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'secondaryInstructions' does not exist on... Remove this comment to see the full error message
|
||||||
secondaryInstructions,
|
secondaryInstructions,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'secondaryInput' does not exist on type '... Remove this comment to see the full error message
|
||||||
secondaryInput,
|
secondaryInput,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleCancel' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
handleCancel,
|
handleCancel,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleSubmit' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'primaryButtonText' does not exist on typ... Remove this comment to see the full error message
|
||||||
primaryButtonText,
|
primaryButtonText,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'secondaryButtonText' does not exist on t... Remove this comment to see the full error message
|
||||||
secondaryButtonText,
|
secondaryButtonText,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleSecondaryButtonSubmit' does not ex... Remove this comment to see the full error message
|
||||||
handleSecondaryButtonSubmit,
|
handleSecondaryButtonSubmit,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'primaryButtonProps' does not exist on ty... Remove this comment to see the full error message
|
||||||
primaryButtonProps,
|
primaryButtonProps,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -15,30 +15,32 @@ import TermsOfServicePrompt from "./termsPrompt";
|
|||||||
|
|
||||||
import actions from "../actions";
|
import actions from "../actions";
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
loading: state.controls.loading,
|
loading: (state as any).controls.loading,
|
||||||
error: state.controls.error,
|
error: (state as any).controls.error,
|
||||||
graphRenderCounter: state.controls.graphRenderCounter,
|
graphRenderCounter: (state as any).controls.graphRenderCounter,
|
||||||
}))
|
}))
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
/* listen for url changes, fire one when we start the app up */
|
/* listen for url changes, fire one when we start the app up */
|
||||||
window.addEventListener("popstate", this._onURLChanged);
|
window.addEventListener("popstate", this._onURLChanged);
|
||||||
this._onURLChanged();
|
this._onURLChanged();
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
dispatch(actions.doInitialDataLoad(window.location.search));
|
dispatch(actions.doInitialDataLoad(window.location.search));
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onURLChanged() {
|
_onURLChanged() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
dispatch({ type: "url changed", url: document.location.href });
|
dispatch({ type: "url changed", url: document.location.href });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'loading' does not exist on type 'Readonl... Remove this comment to see the full error message
|
||||||
const { loading, error, graphRenderCounter } = this.props;
|
const { loading, error, graphRenderCounter } = this.props;
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
@@ -70,13 +72,15 @@ class App extends React.Component {
|
|||||||
{loading || error ? null : (
|
{loading || error ? null : (
|
||||||
<Layout>
|
<Layout>
|
||||||
<LeftSideBar />
|
<LeftSideBar />
|
||||||
{(viewportRef) => (
|
{(viewportRef: any) => (
|
||||||
<>
|
<>
|
||||||
<MenuBar />
|
<MenuBar />
|
||||||
<Embedding />
|
<Embedding />
|
||||||
<Autosave />
|
<Autosave />
|
||||||
<TermsOfServicePrompt />
|
<TermsOfServicePrompt />
|
||||||
|
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||||
<Legend viewportRef={viewportRef} />
|
<Legend viewportRef={viewportRef} />
|
||||||
|
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ key: any; viewportRef: any; }' is not assi... Remove this comment to see the full error message */}
|
||||||
<Graph key={graphRenderCounter} viewportRef={viewportRef} />
|
<Graph key={graphRenderCounter} viewportRef={viewportRef} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
+32
-18
@@ -11,18 +11,23 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
idhash: state.config?.parameters?.["annotations-user-data-idhash"] ?? null,
|
idhash:
|
||||||
annotations: state.annotations,
|
(state as any).config?.parameters?.["annotations-user-data-idhash"] ?? null,
|
||||||
auth: state.config?.authentication,
|
annotations: (state as any).annotations,
|
||||||
userInfo: state.userInfo,
|
auth: (state as any).config?.authentication,
|
||||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
userInfo: (state as any).userInfo,
|
||||||
|
writableCategoriesEnabled:
|
||||||
|
(state as any).config?.parameters?.annotations ?? false,
|
||||||
writableGenesetsEnabled: !(
|
writableGenesetsEnabled: !(
|
||||||
state.config?.parameters?.annotations_genesets_readonly ?? true
|
(state as any).config?.parameters?.annotations_genesets_readonly ?? true
|
||||||
),
|
),
|
||||||
}))
|
}))
|
||||||
class FilenameDialog extends React.Component {
|
class FilenameDialog extends React.Component<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
filenameText: "",
|
filenameText: "",
|
||||||
@@ -32,9 +37,9 @@ class FilenameDialog extends React.Component {
|
|||||||
dismissFilenameDialog = () => {};
|
dismissFilenameDialog = () => {};
|
||||||
|
|
||||||
handleCreateFilename = () => {
|
handleCreateFilename = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { filenameText } = this.state;
|
const { filenameText } = this.state;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "set annotations collection name",
|
type: "set annotations collection name",
|
||||||
data: filenameText,
|
data: filenameText,
|
||||||
@@ -45,26 +50,26 @@ class FilenameDialog extends React.Component {
|
|||||||
const legalNames = /^\w+$/;
|
const legalNames = /^\w+$/;
|
||||||
const { filenameText } = this.state;
|
const { filenameText } = this.state;
|
||||||
let err = false;
|
let err = false;
|
||||||
|
|
||||||
if (filenameText === "") {
|
if (filenameText === "") {
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'boolean'.
|
||||||
err = "empty_string";
|
err = "empty_string";
|
||||||
} else if (!legalNames.test(filenameText)) {
|
} else if (!legalNames.test(filenameText)) {
|
||||||
/*
|
/*
|
||||||
IMPORTANT: this test must ultimately match the test applied by the
|
IMPORTANT: this test must ultimately match the test applied by the
|
||||||
backend, which is designed to ensure a safe file name can be created
|
backend, which is designed to ensure a safe file name can be created
|
||||||
from the data collection name. If you change this, you will also need
|
from the data collection name. If you change this, you will also need
|
||||||
to change the validation code in the backend, or it will have no effect.
|
to change the validation code in the backend, or it will have no effect.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'boolean'.
|
||||||
err = "characters";
|
err = "characters";
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
filenameErrorMessage = () => {
|
filenameErrorMessage = () => {
|
||||||
const err = this.filenameError();
|
const err = this.filenameError();
|
||||||
let markup = null;
|
let markup = null;
|
||||||
|
// @ts-expect-error ts-migrate(2367) FIXME: This condition will always return 'false' since th... Remove this comment to see the full error message
|
||||||
if (err === "empty_string") {
|
if (err === "empty_string") {
|
||||||
markup = (
|
markup = (
|
||||||
<span
|
<span
|
||||||
@@ -78,6 +83,7 @@ class FilenameDialog extends React.Component {
|
|||||||
Name cannot be blank
|
Name cannot be blank
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
// @ts-expect-error ts-migrate(2367) FIXME: This condition will always return 'false' since th... Remove this comment to see the full error message
|
||||||
} else if (err === "characters") {
|
} else if (err === "characters") {
|
||||||
markup = (
|
markup = (
|
||||||
<span
|
<span
|
||||||
@@ -97,14 +103,18 @@ class FilenameDialog extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableCategoriesEnabled' does not exis... Remove this comment to see the full error message
|
||||||
writableCategoriesEnabled,
|
writableCategoriesEnabled,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableGenesetsEnabled' does not exist ... Remove this comment to see the full error message
|
||||||
writableGenesetsEnabled,
|
writableGenesetsEnabled,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annotations' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
annotations,
|
annotations,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'idhash' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
idhash,
|
idhash,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'userInfo' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
userInfo,
|
userInfo,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { filenameText } = this.state;
|
const { filenameText } = this.state;
|
||||||
|
|
||||||
return (writableCategoriesEnabled || writableGenesetsEnabled) &&
|
return (writableCategoriesEnabled || writableGenesetsEnabled) &&
|
||||||
annotations.promptForFilename &&
|
annotations.promptForFilename &&
|
||||||
!annotations.dataCollectionNameIsReadOnly &&
|
!annotations.dataCollectionNameIsReadOnly &&
|
||||||
@@ -128,6 +138,7 @@ class FilenameDialog extends React.Component {
|
|||||||
<InputGroup
|
<InputGroup
|
||||||
autoFocus
|
autoFocus
|
||||||
value={filenameText}
|
value={filenameText}
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
intent={this.filenameError(filenameText) ? "warning" : "none"}
|
intent={this.filenameError(filenameText) ? "warning" : "none"}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
this.setState({ filenameText: e.target.value })
|
this.setState({ filenameText: e.target.value })
|
||||||
@@ -138,12 +149,14 @@ class FilenameDialog extends React.Component {
|
|||||||
<p
|
<p
|
||||||
style={{
|
style={{
|
||||||
marginTop: 7,
|
marginTop: 7,
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
visibility: this.filenameError(filenameText)
|
visibility: this.filenameError(filenameText)
|
||||||
? "visible"
|
? "visible"
|
||||||
: "hidden",
|
: "hidden",
|
||||||
color: Colors.ORANGE3,
|
color: Colors.ORANGE3,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1. */}
|
||||||
{this.filenameErrorMessage(filenameText)}
|
{this.filenameErrorMessage(filenameText)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -171,6 +184,7 @@ class FilenameDialog extends React.Component {
|
|||||||
<Button onClick={this.dismissFilenameDialog}>Cancel</Button>
|
<Button onClick={this.dismissFilenameDialog}>Cancel</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||||
disabled={!filenameText || this.filenameError(filenameText)}
|
disabled={!filenameText || this.filenameError(filenameText)}
|
||||||
onClick={this.handleCreateFilename}
|
onClick={this.handleCreateFilename}
|
||||||
intent="primary"
|
intent="primary"
|
||||||
+30
-15
@@ -3,23 +3,30 @@ import { connect } from "react-redux";
|
|||||||
import actions from "../../actions";
|
import actions from "../../actions";
|
||||||
import FilenameDialog from "./filenameDialog";
|
import FilenameDialog from "./filenameDialog";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
obsAnnotationSaveInProgress:
|
obsAnnotationSaveInProgress:
|
||||||
state.autosave?.obsAnnotationSaveInProgress ?? false,
|
(state as any).autosave?.obsAnnotationSaveInProgress ?? false,
|
||||||
genesetSaveInProgress: state.autosave?.genesetSaveInProgress ?? false,
|
genesetSaveInProgress:
|
||||||
error: state.autosave?.error,
|
(state as any).autosave?.genesetSaveInProgress ?? false,
|
||||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
error: (state as any).autosave?.error,
|
||||||
|
writableCategoriesEnabled:
|
||||||
|
(state as any).config?.parameters?.annotations ?? false,
|
||||||
writableGenesetsEnabled: !(
|
writableGenesetsEnabled: !(
|
||||||
state.config?.parameters?.annotations_genesets_readonly ?? true
|
(state as any).config?.parameters?.annotations_genesets_readonly ?? true
|
||||||
),
|
),
|
||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: (state as any).annoMatrix,
|
||||||
genesets: state.genesets,
|
genesets: (state as any).genesets,
|
||||||
lastSavedAnnoMatrix: state.autosave?.lastSavedAnnoMatrix,
|
lastSavedAnnoMatrix: (state as any).autosave?.lastSavedAnnoMatrix,
|
||||||
lastSavedGenesets: state.autosave?.lastSavedGenesets,
|
lastSavedGenesets: (state as any).autosave?.lastSavedGenesets,
|
||||||
}))
|
}))
|
||||||
class Autosave extends React.Component {
|
class Autosave extends React.Component<{}, State> {
|
||||||
constructor(props) {
|
clearInterval: any;
|
||||||
|
|
||||||
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
timer: null,
|
timer: null,
|
||||||
@@ -27,8 +34,8 @@ class Autosave extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableCategoriesEnabled' does not exis... Remove this comment to see the full error message
|
||||||
const { writableCategoriesEnabled, writableGenesetsEnabled } = this.props;
|
const { writableCategoriesEnabled, writableGenesetsEnabled } = this.props;
|
||||||
|
|
||||||
let { timer } = this.state;
|
let { timer } = this.state;
|
||||||
if (timer) clearInterval(timer);
|
if (timer) clearInterval(timer);
|
||||||
if (writableCategoriesEnabled || writableGenesetsEnabled) {
|
if (writableCategoriesEnabled || writableGenesetsEnabled) {
|
||||||
@@ -46,8 +53,11 @@ class Autosave extends React.Component {
|
|||||||
|
|
||||||
tick = () => {
|
tick = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsAnnotationSaveInProgress' does not ex... Remove this comment to see the full error message
|
||||||
obsAnnotationSaveInProgress,
|
obsAnnotationSaveInProgress,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'genesetSaveInProgress' does not exist on... Remove this comment to see the full error message
|
||||||
genesetSaveInProgress,
|
genesetSaveInProgress,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (!obsAnnotationSaveInProgress && this.needToSaveObsAnnotations()) {
|
if (!obsAnnotationSaveInProgress && this.needToSaveObsAnnotations()) {
|
||||||
@@ -60,12 +70,14 @@ class Autosave extends React.Component {
|
|||||||
|
|
||||||
needToSaveObsAnnotations = () => {
|
needToSaveObsAnnotations = () => {
|
||||||
/* return true if we need to save obs cell labels, false if we don't */
|
/* return true if we need to save obs cell labels, false if we don't */
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
const { annoMatrix, lastSavedAnnoMatrix } = this.props;
|
const { annoMatrix, lastSavedAnnoMatrix } = this.props;
|
||||||
return actions.needToSaveObsAnnotations(annoMatrix, lastSavedAnnoMatrix);
|
return actions.needToSaveObsAnnotations(annoMatrix, lastSavedAnnoMatrix);
|
||||||
};
|
};
|
||||||
|
|
||||||
needToSaveGenesets = () => {
|
needToSaveGenesets = () => {
|
||||||
/* return true if we need to save gene ses, false if we do not */
|
/* return true if we need to save gene ses, false if we do not */
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'genesets' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { genesets, lastSavedGenesets } = this.props;
|
const { genesets, lastSavedGenesets } = this.props;
|
||||||
return genesets.initialized && genesets.genesets !== lastSavedGenesets;
|
return genesets.initialized && genesets.genesets !== lastSavedGenesets;
|
||||||
};
|
};
|
||||||
@@ -75,11 +87,13 @@ class Autosave extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveInProgress() {
|
saveInProgress() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'obsAnnotationSaveInProgress' does not ex... Remove this comment to see the full error message
|
||||||
const { obsAnnotationSaveInProgress, genesetSaveInProgress } = this.props;
|
const { obsAnnotationSaveInProgress, genesetSaveInProgress } = this.props;
|
||||||
return obsAnnotationSaveInProgress || genesetSaveInProgress;
|
return obsAnnotationSaveInProgress || genesetSaveInProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
statusMessage() {
|
statusMessage() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'error' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
const { error } = this.props;
|
const { error } = this.props;
|
||||||
if (error) {
|
if (error) {
|
||||||
return `Autosave error: ${error}`;
|
return `Autosave error: ${error}`;
|
||||||
@@ -89,14 +103,15 @@ class Autosave extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableCategoriesEnabled' does not exis... Remove this comment to see the full error message
|
||||||
writableCategoriesEnabled,
|
writableCategoriesEnabled,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableGenesetsEnabled' does not exist ... Remove this comment to see the full error message
|
||||||
writableGenesetsEnabled,
|
writableGenesetsEnabled,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'lastSavedAnnoMatrix' does not exist on t... Remove this comment to see the full error message
|
||||||
lastSavedAnnoMatrix,
|
lastSavedAnnoMatrix,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const initialDataLoadComplete = lastSavedAnnoMatrix;
|
const initialDataLoadComplete = lastSavedAnnoMatrix;
|
||||||
|
|
||||||
if (!writableCategoriesEnabled && !writableGenesetsEnabled) return null;
|
if (!writableCategoriesEnabled && !writableGenesetsEnabled) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="autosave"
|
id="autosave"
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
const ErrorLoading = ({ displayName, zebra }) => {
|
const ErrorLoading = ({ displayName, zebra }: any) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
+8
@@ -2,13 +2,21 @@ import React from "react";
|
|||||||
|
|
||||||
const HistogramFooter = React.memo(
|
const HistogramFooter = React.memo(
|
||||||
({
|
({
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'displayName' does not exist on type '{ c... Remove this comment to see the full error message
|
||||||
displayName,
|
displayName,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'hideRanges' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
hideRanges,
|
hideRanges,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'rangeMin' does not exist on type '{ chil... Remove this comment to see the full error message
|
||||||
rangeMin,
|
rangeMin,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'rangeMax' does not exist on type '{ chil... Remove this comment to see the full error message
|
||||||
rangeMax,
|
rangeMax,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'rangeColorMin' does not exist on type '{... Remove this comment to see the full error message
|
||||||
rangeColorMin,
|
rangeColorMin,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'rangeColorMax' does not exist on type '{... Remove this comment to see the full error message
|
||||||
rangeColorMax,
|
rangeColorMax,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type '{ childre... Remove this comment to see the full error message
|
||||||
isObs,
|
isObs,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isGeneSetSummary' does not exist on type... Remove this comment to see the full error message
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
+9
@@ -5,14 +5,23 @@ import * as globals from "../../globals";
|
|||||||
|
|
||||||
const HistogramHeader = React.memo(
|
const HistogramHeader = React.memo(
|
||||||
({
|
({
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'fieldId' does not exist on type '{ child... Remove this comment to see the full error message
|
||||||
fieldId,
|
fieldId,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorBy' does not exist on type '{ chi... Remove this comment to see the full error message
|
||||||
isColorBy,
|
isColorBy,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onColorByClick' does not exist on type '... Remove this comment to see the full error message
|
||||||
onColorByClick,
|
onColorByClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onRemoveClick' does not exist on type '{... Remove this comment to see the full error message
|
||||||
onRemoveClick,
|
onRemoveClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterPlotX' does not exist on type '... Remove this comment to see the full error message
|
||||||
isScatterPlotX,
|
isScatterPlotX,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterPlotY' does not exist on type '... Remove this comment to see the full error message
|
||||||
isScatterPlotY,
|
isScatterPlotY,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onScatterPlotXClick' does not exist on t... Remove this comment to see the full error message
|
||||||
onScatterPlotXClick,
|
onScatterPlotXClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onScatterPlotYClick' does not exist on t... Remove this comment to see the full error message
|
||||||
onScatterPlotYClick,
|
onScatterPlotYClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type '{ childre... Remove this comment to see the full error message
|
||||||
isObs,
|
isObs,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
+14
-3
@@ -18,7 +18,7 @@ const Histogram = ({
|
|||||||
isColorBy,
|
isColorBy,
|
||||||
selectionRange,
|
selectionRange,
|
||||||
mini,
|
mini,
|
||||||
}) => {
|
}: any) => {
|
||||||
const svgRef = useRef(null);
|
const svgRef = useRef(null);
|
||||||
const [brush, setBrush] = useState(null);
|
const [brush, setBrush] = useState(null);
|
||||||
|
|
||||||
@@ -69,14 +69,18 @@ const Histogram = ({
|
|||||||
.data(bins)
|
.data(bins)
|
||||||
.enter()
|
.enter()
|
||||||
.append("rect")
|
.append("rect")
|
||||||
|
// @ts-expect-error ts-migrate(6133) FIXME: 'd' is declared but its value is never read.
|
||||||
.attr("x", (d, i) => x(binStart(i)) + 1)
|
.attr("x", (d, i) => x(binStart(i)) + 1)
|
||||||
.attr("y", (d) => y(d))
|
.attr("y", (d) => y(d))
|
||||||
|
// @ts-expect-error ts-migrate(6133) FIXME: 'd' is declared but its value is never read.
|
||||||
.attr("width", (d, i) => x(binEnd(i)) - x(binStart(i)) - binPadding)
|
.attr("width", (d, i) => x(binEnd(i)) - x(binStart(i)) - binPadding)
|
||||||
.attr("height", (d) => y(0) - y(d))
|
.attr("height", (d) => y(0) - y(d))
|
||||||
.style(
|
.style(
|
||||||
"fill",
|
"fill",
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
isColorBy
|
isColorBy
|
||||||
? (d, i) => colorScale(histogramScale(binStart(i)))
|
? // @ts-expect-error ts-migrate(6133) FIXME: 'd' is declared but its value is never read.
|
||||||
|
(d: any, i: any) => colorScale(histogramScale(binStart(i)))
|
||||||
: defaultBarColor
|
: defaultBarColor
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -101,6 +105,7 @@ const Histogram = ({
|
|||||||
const brushXselection = container
|
const brushXselection = container
|
||||||
.insert("g")
|
.insert("g")
|
||||||
.attr("class", "brush")
|
.attr("class", "brush")
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
.attr("data-testid", `${svgRef.current.dataset.testid}-brushable-area`)
|
.attr("data-testid", `${svgRef.current.dataset.testid}-brushable-area`)
|
||||||
.call(brushX);
|
.call(brushX);
|
||||||
|
|
||||||
@@ -113,6 +118,7 @@ const Histogram = ({
|
|||||||
d3
|
d3
|
||||||
.axisBottom(x)
|
.axisBottom(x)
|
||||||
.ticks(4)
|
.ticks(4)
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
.tickFormat(d3.format(maybeScientific(x)))
|
.tickFormat(d3.format(maybeScientific(x)))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -126,8 +132,9 @@ const Histogram = ({
|
|||||||
.axisRight(y)
|
.axisRight(y)
|
||||||
.ticks(3)
|
.ticks(3)
|
||||||
.tickFormat(
|
.tickFormat(
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
d3.format(
|
d3.format(
|
||||||
y.domain().some((n) => Math.abs(n) >= 10000) ? ".0e" : ","
|
y.domain().some((n: any) => Math.abs(n) >= 10000) ? ".0e" : ","
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -137,6 +144,7 @@ const Histogram = ({
|
|||||||
svg.selectAll(".axis path").style("stroke", "rgb(230,230,230)");
|
svg.selectAll(".axis path").style("stroke", "rgb(230,230,230)");
|
||||||
svg.selectAll(".axis line").style("stroke", "rgb(230,230,230)");
|
svg.selectAll(".axis line").style("stroke", "rgb(230,230,230)");
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ brushX: d3.BrushBehavior<unkno... Remove this comment to see the full error message
|
||||||
setBrush({ brushX, brushXselection });
|
setBrush({ brushX, brushXselection });
|
||||||
}
|
}
|
||||||
}, [histogram, isColorBy]);
|
}, [histogram, isColorBy]);
|
||||||
@@ -146,6 +154,7 @@ const Histogram = ({
|
|||||||
paint/update selection brush
|
paint/update selection brush
|
||||||
*/
|
*/
|
||||||
if (!brush) return;
|
if (!brush) return;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'brushX' does not exist on type 'null'.
|
||||||
const { brushX, brushXselection } = brush;
|
const { brushX, brushXselection } = brush;
|
||||||
const selection = d3.brushSelection(brushXselection.node());
|
const selection = d3.brushSelection(brushXselection.node());
|
||||||
if (!selectionRange && selection) {
|
if (!selectionRange && selection) {
|
||||||
@@ -162,7 +171,9 @@ const Histogram = ({
|
|||||||
} else {
|
} else {
|
||||||
/* there is an active selection and a brush - make sure they match */
|
/* there is an active selection and a brush - make sure they match */
|
||||||
const moveDeltaThreshold = 1;
|
const moveDeltaThreshold = 1;
|
||||||
|
// @ts-expect-error ts-migrate(2363) FIXME: The right-hand side of an arithmetic operation mus... Remove this comment to see the full error message
|
||||||
const dX0 = Math.abs(x0 - selection[0]);
|
const dX0 = Math.abs(x0 - selection[0]);
|
||||||
|
// @ts-expect-error ts-migrate(2363) FIXME: The right-hand side of an arithmetic operation mus... Remove this comment to see the full error message
|
||||||
const dX1 = Math.abs(x1 - selection[1]);
|
const dX1 = Math.abs(x1 - selection[1]);
|
||||||
/*
|
/*
|
||||||
only update the brush if it is grossly incorrect,
|
only update the brush if it is grossly incorrect,
|
||||||
+95
-58
@@ -29,27 +29,31 @@ const MARGIN_MINI = {
|
|||||||
const WIDTH_MINI = 120 - MARGIN_MINI.LEFT - MARGIN_MINI.RIGHT;
|
const WIDTH_MINI = 120 - MARGIN_MINI.LEFT - MARGIN_MINI.RIGHT;
|
||||||
const HEIGHT_MINI = 15 - MARGIN_MINI.TOP - MARGIN_MINI.BOTTOM;
|
const HEIGHT_MINI = 15 - MARGIN_MINI.TOP - MARGIN_MINI.BOTTOM;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state, ownProps) => {
|
@connect((state, ownProps) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type '{}'.
|
||||||
const { isObs, isUserDefined, isGeneSetSummary, field } = ownProps;
|
const { isObs, isUserDefined, isGeneSetSummary, field } = ownProps;
|
||||||
const myName = makeContinuousDimensionName(
|
const myName = makeContinuousDimensionName(
|
||||||
{ isObs, isUserDefined, isGeneSetSummary },
|
{ isObs, isUserDefined, isGeneSetSummary },
|
||||||
field
|
field
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: (state as any).annoMatrix,
|
||||||
isScatterplotXXaccessor: state.controls.scatterplotXXaccessor === field,
|
isScatterplotXXaccessor:
|
||||||
isScatterplotYYaccessor: state.controls.scatterplotYYaccessor === field,
|
(state as any).controls.scatterplotXXaccessor === field,
|
||||||
continuousSelectionRange: state.continuousSelection[myName],
|
isScatterplotYYaccessor:
|
||||||
isColorAccessor: state.colors.colorAccessor === field,
|
(state as any).controls.scatterplotYYaccessor === field,
|
||||||
|
continuousSelectionRange: (state as any).continuousSelection[myName],
|
||||||
|
isColorAccessor: (state as any).colors.colorAccessor === field,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class HistogramBrush extends React.PureComponent {
|
class HistogramBrush extends React.PureComponent {
|
||||||
static watchAsync(props, prevProps) {
|
static watchAsync(props: any, prevProps: any) {
|
||||||
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memoized closure to prevent HistogramHeader unecessary repaint */
|
/* memoized closure to prevent HistogramHeader unecessary repaint */
|
||||||
handleColorAction = memoize((dispatch) => (field, isObs) => {
|
handleColorAction = memoize((dispatch) => (field: any, isObs: any) => {
|
||||||
if (isObs) {
|
if (isObs) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "color by continuous metadata",
|
type: "color by continuous metadata",
|
||||||
@@ -60,25 +64,31 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onBrush = (selection, x, eventType) => {
|
// @ts-expect-error ts-migrate(6133) FIXME: 'selection' is declared but its value is never rea... Remove this comment to see the full error message
|
||||||
|
onBrush = (selection: any, x: any, eventType: any) => {
|
||||||
const type = `continuous metadata histogram ${eventType}`;
|
const type = `continuous metadata histogram ${eventType}`;
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'field' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
field,
|
field,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
isObs,
|
isObs,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserDefined' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isGeneSetSummary' does not exist on type... Remove this comment to see the full error message
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// ignore programmatically generated events
|
// ignore programmatically generated events
|
||||||
if (!d3.event.sourceEvent) return;
|
if (!(d3 as any).event.sourceEvent) return;
|
||||||
// ignore cascading events, which are programmatically generated
|
// ignore cascading events, which are programmatically generated
|
||||||
if (d3.event.sourceEvent.sourceEvent) return;
|
if ((d3 as any).event.sourceEvent.sourceEvent) return;
|
||||||
|
|
||||||
const query = this.createQuery();
|
const query = this.createQuery();
|
||||||
const range = d3.event.selection
|
const range = (d3 as any).event.selection
|
||||||
? [x(d3.event.selection[0]), x(d3.event.selection[1])]
|
? [x((d3 as any).event.selection[0]), x((d3 as any).event.selection[1])]
|
||||||
: null;
|
: null;
|
||||||
const otherProps = {
|
const otherProps = {
|
||||||
selection: field,
|
selection: field,
|
||||||
@@ -94,42 +104,52 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
onBrushEnd = (selection, x) => {
|
// @ts-expect-error ts-migrate(6133) FIXME: 'selection' is declared but its value is never rea... Remove this comment to see the full error message
|
||||||
|
onBrushEnd = (selection: any, x: any) => {
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'field' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
field,
|
field,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
isObs,
|
isObs,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserDefined' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isGeneSetSummary' does not exist on type... Remove this comment to see the full error message
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const minAllowedBrushSize = 10;
|
const minAllowedBrushSize = 10;
|
||||||
const smallAmountToAvoidInfiniteLoop = 0.1;
|
const smallAmountToAvoidInfiniteLoop = 0.1;
|
||||||
|
|
||||||
// ignore programmatically generated events
|
// ignore programmatically generated events
|
||||||
if (!d3.event.sourceEvent) return;
|
if (!(d3 as any).event.sourceEvent) return;
|
||||||
// ignore cascading events, which are programmatically generated
|
// ignore cascading events, which are programmatically generated
|
||||||
if (d3.event.sourceEvent.sourceEvent) return;
|
if ((d3 as any).event.sourceEvent.sourceEvent) return;
|
||||||
|
|
||||||
let type;
|
let type;
|
||||||
let range = null;
|
let range = null;
|
||||||
if (d3.event.selection) {
|
if ((d3 as any).event.selection) {
|
||||||
type = "continuous metadata histogram end";
|
type = "continuous metadata histogram end";
|
||||||
if (
|
if (
|
||||||
d3.event.selection[1] - d3.event.selection[0] >
|
(d3 as any).event.selection[1] - (d3 as any).event.selection[0] >
|
||||||
minAllowedBrushSize
|
minAllowedBrushSize
|
||||||
) {
|
) {
|
||||||
range = [x(d3.event.selection[0]), x(d3.event.selection[1])];
|
range = [
|
||||||
|
x((d3 as any).event.selection[0]),
|
||||||
|
x((d3 as any).event.selection[1]),
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
/* the user selected range is too small and will be hidden #587, so take control of it procedurally */
|
/* the user selected range is too small and will be hidden #587, so take control of it procedurally */
|
||||||
/* https://stackoverflow.com/questions/12354729/d3-js-limit-size-of-brush */
|
/* https://stackoverflow.com/questions/12354729/d3-js-limit-size-of-brush */
|
||||||
|
|
||||||
const procedurallyResizedBrushWidth =
|
const procedurallyResizedBrushWidth =
|
||||||
d3.event.selection[0] +
|
(d3 as any).event.selection[0] +
|
||||||
minAllowedBrushSize +
|
minAllowedBrushSize +
|
||||||
smallAmountToAvoidInfiniteLoop; //
|
smallAmountToAvoidInfiniteLoop; //
|
||||||
|
range = [
|
||||||
range = [x(d3.event.selection[0]), x(procedurallyResizedBrushWidth)];
|
x((d3 as any).event.selection[0]),
|
||||||
|
x(procedurallyResizedBrushWidth),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = "continuous metadata histogram cancel";
|
type = "continuous metadata histogram cancel";
|
||||||
@@ -151,6 +171,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleSetGeneAsScatterplotX = () => {
|
handleSetGeneAsScatterplotX = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, field } = this.props;
|
const { dispatch, field } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "set scatterplot x",
|
type: "set scatterplot x",
|
||||||
@@ -159,6 +180,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleSetGeneAsScatterplotY = () => {
|
handleSetGeneAsScatterplotY = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, field } = this.props;
|
const { dispatch, field } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "set scatterplot y",
|
type: "set scatterplot y",
|
||||||
@@ -168,10 +190,15 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
|
|
||||||
removeHistogram = () => {
|
removeHistogram = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'field' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
field,
|
field,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotXXaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotXXaccessor,
|
isScatterplotXXaccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotYYaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotYYaccessor,
|
isScatterplotYYaccessor,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -198,11 +225,13 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchAsyncProps = async () => {
|
fetchAsyncProps = async () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
const { annoMatrix, width } = this.props;
|
const { annoMatrix, width } = this.props;
|
||||||
|
|
||||||
const { isClipped } = annoMatrix;
|
const { isClipped } = annoMatrix;
|
||||||
|
|
||||||
const query = this.createQuery();
|
const query = this.createQuery();
|
||||||
|
// @ts-expect-error ts-migrate(2488) FIXME: Type 'any[] | null' must have a '[Symbol.iterator]... Remove this comment to see the full error message
|
||||||
const df = await annoMatrix.fetch(...query);
|
const df = await annoMatrix.fetch(...query);
|
||||||
const column = df.icol(0);
|
const column = df.icol(0);
|
||||||
|
|
||||||
@@ -261,7 +290,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this -- instance method allows for memoization per annotation
|
// eslint-disable-next-line class-methods-use-this -- instance method allows for memoization per annotation
|
||||||
calcHistogramCache(col, newMargin, newWidth, newHeight) {
|
calcHistogramCache(col: any, newMargin: any, newWidth: any, newHeight: any) {
|
||||||
/*
|
/*
|
||||||
recalculate expensive stuff, notably bins, summaries, etc.
|
recalculate expensive stuff, notably bins, summaries, etc.
|
||||||
*/
|
*/
|
||||||
@@ -269,35 +298,30 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
const summary = col.summarize(); /* this is memoized, so it's free the second time you call it */
|
const summary = col.summarize(); /* this is memoized, so it's free the second time you call it */
|
||||||
const { min: domainMin, max: domainMax } = summary;
|
const { min: domainMin, max: domainMax } = summary;
|
||||||
const numBins = 40;
|
const numBins = 40;
|
||||||
const {
|
const { TOP: topMargin, LEFT: leftMargin } = newMargin;
|
||||||
TOP: topMargin,
|
(histogramCache as any).domain = [domainMin, domainMax];
|
||||||
LEFT: leftMargin,
|
/* doesn't change with mini */ (histogramCache as any).x = d3
|
||||||
} = newMargin; /* changes with mini */
|
|
||||||
|
|
||||||
histogramCache.domain = [
|
|
||||||
domainMin,
|
|
||||||
domainMax,
|
|
||||||
]; /* doesn't change with mini */
|
|
||||||
|
|
||||||
histogramCache.x = d3
|
|
||||||
.scaleLinear()
|
.scaleLinear()
|
||||||
.domain([domainMin, domainMax])
|
.domain([domainMin, domainMax])
|
||||||
.range([leftMargin, leftMargin + newWidth]);
|
.range([leftMargin, leftMargin + newWidth]);
|
||||||
|
|
||||||
histogramCache.bins = col.histogram(numBins, [
|
(histogramCache as any).bins = col.histogram(numBins, [
|
||||||
domainMin,
|
domainMin,
|
||||||
domainMax,
|
domainMax,
|
||||||
]); /* memoized */
|
]);
|
||||||
|
/* memoized */ (histogramCache as any).binWidth =
|
||||||
|
(domainMax - domainMin) / numBins;
|
||||||
|
|
||||||
histogramCache.binWidth = (domainMax - domainMin) / numBins;
|
(histogramCache as any).binStart = (i: any) =>
|
||||||
|
domainMin + i * (histogramCache as any).binWidth;
|
||||||
|
(histogramCache as any).binEnd = (i: any) =>
|
||||||
|
domainMin + (i + 1) * (histogramCache as any).binWidth;
|
||||||
|
|
||||||
histogramCache.binStart = (i) => domainMin + i * histogramCache.binWidth;
|
const yMax = (histogramCache as any).bins.reduce((l: any, r: any) =>
|
||||||
histogramCache.binEnd = (i) =>
|
l > r ? l : r
|
||||||
domainMin + (i + 1) * histogramCache.binWidth;
|
);
|
||||||
|
|
||||||
const yMax = histogramCache.bins.reduce((l, r) => (l > r ? l : r));
|
(histogramCache as any).y = d3
|
||||||
|
|
||||||
histogramCache.y = d3
|
|
||||||
.scaleLinear()
|
.scaleLinear()
|
||||||
.domain([0, yMax])
|
.domain([0, yMax])
|
||||||
.range([topMargin + newHeight, topMargin]);
|
.range([topMargin + newHeight, topMargin]);
|
||||||
@@ -306,13 +330,8 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createQuery() {
|
createQuery() {
|
||||||
const {
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
isObs,
|
const { isObs, isGeneSetSummary, field, setGenes, annoMatrix } = this.props;
|
||||||
isGeneSetSummary,
|
|
||||||
field,
|
|
||||||
setGenes,
|
|
||||||
annoMatrix,
|
|
||||||
} = this.props;
|
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
if (isObs) {
|
if (isObs) {
|
||||||
return ["obs", field];
|
return ["obs", field];
|
||||||
@@ -349,21 +368,35 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
annoMatrix,
|
annoMatrix,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'field' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
field,
|
field,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserDefined' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isGeneSetSummary' does not exist on type... Remove this comment to see the full error message
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotXXaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotXXaccessor,
|
isScatterplotXXaccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotYYaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotYYaccessor,
|
isScatterplotYYaccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'zebra' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
zebra,
|
zebra,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'continuousSelectionRange' does not exist... Remove this comment to see the full error message
|
||||||
continuousSelectionRange,
|
continuousSelectionRange,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isObs' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
isObs,
|
isObs,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'mini' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||||
mini,
|
mini,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'setGenes' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
setGenes,
|
setGenes,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'width' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
let { width } = this.props;
|
let { width } = this.props;
|
||||||
if (!width) {
|
if (!width) {
|
||||||
width = mini ? WIDTH_MINI : WIDTH;
|
width = mini ? WIDTH_MINI : WIDTH;
|
||||||
@@ -392,7 +425,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
</Async.Rejected>
|
</Async.Rejected>
|
||||||
<Async.Fulfilled>
|
<Async.Fulfilled>
|
||||||
{(asyncProps) =>
|
{(asyncProps) =>
|
||||||
asyncProps.OK2Render ? (
|
(asyncProps as any).OK2Render ? (
|
||||||
<div
|
<div
|
||||||
id={`histogram_${fieldForId}`}
|
id={`histogram_${fieldForId}`}
|
||||||
data-testid={`histogram-${field}`}
|
data-testid={`histogram-${field}`}
|
||||||
@@ -404,6 +437,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
>
|
>
|
||||||
{!mini && isObs ? (
|
{!mini && isObs ? (
|
||||||
<HistogramHeader
|
<HistogramHeader
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ fieldId: any; isColorBy: any; isObs: any; ... Remove this comment to see the full error message
|
||||||
fieldId={field}
|
fieldId={field}
|
||||||
isColorBy={isColorAccessor}
|
isColorBy={isColorAccessor}
|
||||||
isObs={isObs}
|
isObs={isObs}
|
||||||
@@ -422,9 +456,11 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
<Histogram
|
<Histogram
|
||||||
field={field}
|
field={field}
|
||||||
fieldForId={fieldForId}
|
fieldForId={fieldForId}
|
||||||
display={asyncProps.isSingleValue ? "none" : "block"}
|
display={(asyncProps as any).isSingleValue ? "none" : "block"}
|
||||||
histogram={
|
histogram={
|
||||||
mini ? asyncProps.miniHistogram : asyncProps.histogram
|
mini
|
||||||
|
? (asyncProps as any).miniHistogram
|
||||||
|
: (asyncProps as any).histogram
|
||||||
}
|
}
|
||||||
width={width}
|
width={width}
|
||||||
height={mini ? HEIGHT_MINI : HEIGHT}
|
height={mini ? HEIGHT_MINI : HEIGHT}
|
||||||
@@ -437,14 +473,15 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
/>
|
/>
|
||||||
{!mini && (
|
{!mini && (
|
||||||
<HistogramFooter
|
<HistogramFooter
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isGeneSetSummary: any; isObs: any; display... Remove this comment to see the full error message
|
||||||
isGeneSetSummary={isGeneSetSummary}
|
isGeneSetSummary={isGeneSetSummary}
|
||||||
isObs={isObs}
|
isObs={isObs}
|
||||||
displayName={field}
|
displayName={field}
|
||||||
hideRanges={asyncProps.isSingleValue}
|
hideRanges={(asyncProps as any).isSingleValue}
|
||||||
rangeMin={asyncProps.unclippedRange[0]}
|
rangeMin={(asyncProps as any).unclippedRange[0]}
|
||||||
rangeMax={asyncProps.unclippedRange[1]}
|
rangeMax={(asyncProps as any).unclippedRange[1]}
|
||||||
rangeColorMin={asyncProps.unclippedRangeColor[0]}
|
rangeColorMin={(asyncProps as any).unclippedRangeColor[0]}
|
||||||
rangeColorMax={asyncProps.unclippedRangeColor[1]}
|
rangeColorMax={(asyncProps as any).unclippedRangeColor[1]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
+1
-1
@@ -3,7 +3,7 @@ import { Button } from "@blueprintjs/core";
|
|||||||
|
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
const StillLoading = ({ zebra, displayName }) => {
|
const StillLoading = ({ zebra, displayName }: any) => {
|
||||||
/*
|
/*
|
||||||
Render a loading indicator for the field.
|
Render a loading indicator for the field.
|
||||||
*/
|
*/
|
||||||
+9
-2
@@ -2,16 +2,21 @@ import React from "react";
|
|||||||
import { Button, MenuItem } from "@blueprintjs/core";
|
import { Button, MenuItem } from "@blueprintjs/core";
|
||||||
import { Select } from "@blueprintjs/select";
|
import { Select } from "@blueprintjs/select";
|
||||||
|
|
||||||
class DuplicateCategorySelect extends React.PureComponent {
|
type State = any;
|
||||||
constructor(props) {
|
|
||||||
|
class DuplicateCategorySelect extends React.PureComponent<{}, State> {
|
||||||
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'allCategoryNames' does not exist on type... Remove this comment to see the full error message
|
||||||
allCategoryNames,
|
allCategoryNames,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryToDuplicate' does not exist on t... Remove this comment to see the full error message
|
||||||
categoryToDuplicate,
|
categoryToDuplicate,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleModalDuplicateCategorySelection' d... Remove this comment to see the full error message
|
||||||
handleModalDuplicateCategorySelection,
|
handleModalDuplicateCategorySelection,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
@@ -31,7 +36,9 @@ class DuplicateCategorySelect extends React.PureComponent {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
data-testclass="duplicate-category-dropdown-option"
|
data-testclass="duplicate-category-dropdown-option"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'unknown' is not assignable to type 'Key | nu... Remove this comment to see the full error message
|
||||||
key={d}
|
key={d}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'unknown' is not assignable to type 'ReactNod... Remove this comment to see the full error message
|
||||||
text={d}
|
text={d}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
+23
-14
@@ -5,20 +5,24 @@ import LabelInput from "../../labelInput";
|
|||||||
import { labelPrompt, isLabelErroneous } from "../labelUtil";
|
import { labelPrompt, isLabelErroneous } from "../labelUtil";
|
||||||
import actions from "../../../actions";
|
import actions from "../../../actions";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
schema: state.annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
obsCrossfilter: state.obsCrossfilter,
|
obsCrossfilter: (state as any).obsCrossfilter,
|
||||||
}))
|
}))
|
||||||
class Category extends React.PureComponent {
|
class Category extends React.PureComponent<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
newLabelText: "",
|
newLabelText: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
disableAddNewLabelMode = (e) => {
|
disableAddNewLabelMode = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
this.setState({
|
this.setState({
|
||||||
newLabelText: "",
|
newLabelText: "",
|
||||||
@@ -29,10 +33,11 @@ class Category extends React.PureComponent {
|
|||||||
if (e) e.preventDefault();
|
if (e) e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAddNewLabelToCategory = (e) => {
|
handleAddNewLabelToCategory = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
const { newLabelText } = this.state;
|
const { newLabelText } = this.state;
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
this.disableAddNewLabelMode();
|
this.disableAddNewLabelMode();
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.annotationCreateLabelInCategory(
|
actions.annotationCreateLabelInCategory(
|
||||||
@@ -44,10 +49,11 @@ class Category extends React.PureComponent {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
addLabelAndAssignCells = (e) => {
|
addLabelAndAssignCells = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
const { newLabelText } = this.state;
|
const { newLabelText } = this.state;
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
this.disableAddNewLabelMode();
|
this.disableAddNewLabelMode();
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.annotationCreateLabelInCategory(metadataField, newLabelText, true)
|
actions.annotationCreateLabelInCategory(metadataField, newLabelText, true)
|
||||||
@@ -55,26 +61,28 @@ class Category extends React.PureComponent {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
labelNameError = (name) => {
|
labelNameError = (name: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField, schema } = this.props;
|
const { metadataField, schema } = this.props;
|
||||||
return isLabelErroneous(name, metadataField, schema);
|
return isLabelErroneous(name, metadataField, schema);
|
||||||
};
|
};
|
||||||
|
|
||||||
instruction = (label) => {
|
instruction = (label: any) => {
|
||||||
return labelPrompt(this.labelNameError(label), "New, unique label", ":");
|
return labelPrompt(this.labelNameError(label), "New, unique label", ":");
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChangeOrSelect = (label) => {
|
handleChangeOrSelect = (label: any) => {
|
||||||
this.setState({ newLabelText: label });
|
this.setState({ newLabelText: label });
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { newLabelText } = this.state;
|
const { newLabelText } = this.state;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField, annotations, obsCrossfilter } = this.props;
|
const { metadataField, annotations, obsCrossfilter } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AnnoDialog
|
<AnnoDialog
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isActive: any; inputProps: { "data-testid"... Remove this comment to see the full error message
|
||||||
isActive={
|
isActive={
|
||||||
annotations.isAddingNewLabel &&
|
annotations.isAddingNewLabel &&
|
||||||
annotations.categoryAddingNewLabel === metadataField
|
annotations.categoryAddingNewLabel === metadataField
|
||||||
@@ -95,6 +103,7 @@ class Category extends React.PureComponent {
|
|||||||
handleCancel={this.disableAddNewLabelMode}
|
handleCancel={this.disableAddNewLabelMode}
|
||||||
annoInput={
|
annoInput={
|
||||||
<LabelInput
|
<LabelInput
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ labelSuggestions: null; onChange: (label: ... Remove this comment to see the full error message
|
||||||
labelSuggestions={null}
|
labelSuggestions={null}
|
||||||
onChange={this.handleChangeOrSelect}
|
onChange={this.handleChangeOrSelect}
|
||||||
onSelect={this.handleChangeOrSelect}
|
onSelect={this.handleChangeOrSelect}
|
||||||
+34
-27
@@ -7,25 +7,30 @@ import { labelPrompt } from "../labelUtil";
|
|||||||
import { AnnotationsHelpers } from "../../../util/stateManager";
|
import { AnnotationsHelpers } from "../../../util/stateManager";
|
||||||
import actions from "../../../actions";
|
import actions from "../../../actions";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
schema: state.annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
}))
|
}))
|
||||||
class AnnoDialogEditCategoryName extends React.PureComponent {
|
class AnnoDialogEditCategoryName extends React.PureComponent<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
newCategoryText: props.metadataField,
|
newCategoryText: props.metadataField,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeOrSelect = (name) => {
|
handleChangeOrSelect = (name: any) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
newCategoryText: name,
|
newCategoryText: name,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
disableEditCategoryMode = () => {
|
disableEditCategoryMode = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: disable category edit mode",
|
type: "annotation: disable category edit mode",
|
||||||
@@ -33,17 +38,19 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
|||||||
this.setState({ newCategoryText: metadataField });
|
this.setState({ newCategoryText: metadataField });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEditCategory = (e) => {
|
handleEditCategory = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
const { newCategoryText } = this.state;
|
const { newCategoryText } = this.state;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
test for uniqueness against *all* annotation names, not just the subset
|
test for uniqueness against *all* annotation names, not just the subset
|
||||||
we render as categorical.
|
we render as categorical.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
const { schema } = this.props;
|
const { schema } = this.props;
|
||||||
const allCategoryNames = schema.annotations.obs.columns.map((c) => c.name);
|
const allCategoryNames = schema.annotations.obs.columns.map(
|
||||||
|
(c: any) => c.name
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
(allCategoryNames.indexOf(newCategoryText) > -1 &&
|
(allCategoryNames.indexOf(newCategoryText) > -1 &&
|
||||||
newCategoryText !== metadataField) ||
|
newCategoryText !== metadataField) ||
|
||||||
@@ -51,9 +58,7 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disableEditCategoryMode();
|
this.disableEditCategoryMode();
|
||||||
|
|
||||||
if (metadataField !== newCategoryText)
|
if (metadataField !== newCategoryText)
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.annotationRenameCategoryAction(metadataField, newCategoryText)
|
actions.annotationRenameCategoryAction(metadataField, newCategoryText)
|
||||||
@@ -61,35 +66,34 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
editedCategoryNameError = (name) => {
|
editedCategoryNameError = (name: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField } = this.props;
|
const { metadataField } = this.props;
|
||||||
|
|
||||||
/* check for syntax errors in category name */
|
/* check for syntax errors in category name */
|
||||||
const error = AnnotationsHelpers.annotationNameIsErroneous(name);
|
const error = AnnotationsHelpers.annotationNameIsErroneous(name);
|
||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for duplicative categories */
|
/* check for duplicative categories */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
test for uniqueness against *all* annotation names, not just the subset
|
test for uniqueness against *all* annotation names, not just the subset
|
||||||
we render as categorical.
|
we render as categorical.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
const { schema } = this.props;
|
const { schema } = this.props;
|
||||||
const allCategoryNames = schema.annotations.obs.columns.map((c) => c.name);
|
const allCategoryNames = schema.annotations.obs.columns.map(
|
||||||
|
(c: any) => c.name
|
||||||
|
);
|
||||||
const categoryNameAlreadyExists = allCategoryNames.indexOf(name) > -1;
|
const categoryNameAlreadyExists = allCategoryNames.indexOf(name) > -1;
|
||||||
const sameName = name === metadataField;
|
const sameName = name === metadataField;
|
||||||
if (categoryNameAlreadyExists && !sameName) {
|
if (categoryNameAlreadyExists && !sameName) {
|
||||||
return "duplicate";
|
return "duplicate";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise, no error */
|
/* otherwise, no error */
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
instruction = (name) => {
|
instruction = (name: any) => {
|
||||||
return labelPrompt(
|
return labelPrompt(
|
||||||
this.editedCategoryNameError(name),
|
this.editedCategoryNameError(name),
|
||||||
"New, unique category name",
|
"New, unique category name",
|
||||||
@@ -98,17 +102,19 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
allCategoryNames() {
|
allCategoryNames() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
const { schema } = this.props;
|
const { schema } = this.props;
|
||||||
return schema.annotations.obs.columns.map((c) => c.name);
|
return schema.annotations.obs.columns.map((c: any) => c.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { newCategoryText } = this.state;
|
const { newCategoryText } = this.state;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField, annotations } = this.props;
|
const { metadataField, annotations } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AnnoDialog
|
<AnnoDialog
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isActive: any; inputProps: { "data-testid"... Remove this comment to see the full error message
|
||||||
isActive={
|
isActive={
|
||||||
annotations.isEditingCategoryName &&
|
annotations.isEditingCategoryName &&
|
||||||
annotations.categoryBeingEdited === metadataField
|
annotations.categoryBeingEdited === metadataField
|
||||||
@@ -129,6 +135,7 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
|
|||||||
handleCancel={this.disableEditCategoryMode}
|
handleCancel={this.disableEditCategoryMode}
|
||||||
annoInput={
|
annoInput={
|
||||||
<LabelInput
|
<LabelInput
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ label: any; labelSuggestions: null; onChan... Remove this comment to see the full error message
|
||||||
label={newCategoryText}
|
label={newCategoryText}
|
||||||
labelSuggestions={null}
|
labelSuggestions={null}
|
||||||
onChange={this.handleChangeOrSelect}
|
onChange={this.handleChangeOrSelect}
|
||||||
+15
-5
@@ -16,16 +16,20 @@ import { IconNames } from "@blueprintjs/icons";
|
|||||||
import * as globals from "../../../globals";
|
import * as globals from "../../../globals";
|
||||||
import actions from "../../../actions";
|
import actions from "../../../actions";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
}))
|
}))
|
||||||
class AnnoMenuCategory extends React.PureComponent {
|
class AnnoMenuCategory extends React.PureComponent<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
activateAddNewLabelMode = () => {
|
activateAddNewLabelMode = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: activate add new label mode",
|
type: "annotation: activate add new label mode",
|
||||||
@@ -34,8 +38,8 @@ class AnnoMenuCategory extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
activateEditCategoryMode = () => {
|
activateEditCategoryMode = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: activate category edit mode",
|
type: "annotation: activate category edit mode",
|
||||||
data: metadataField,
|
data: metadataField,
|
||||||
@@ -43,20 +47,26 @@ class AnnoMenuCategory extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleDeleteCategory = () => {
|
handleDeleteCategory = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch(actions.annotationDeleteCategoryAction(metadataField));
|
dispatch(actions.annotationDeleteCategoryAction(metadataField));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annotations' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
annotations,
|
annotations,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'createText' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
createText,
|
createText,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'editText' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
editText,
|
editText,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'deleteText' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
deleteText,
|
deleteText,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isUserAnno ? (
|
{isUserAnno ? (
|
||||||
+97
-24
@@ -31,33 +31,39 @@ const LABEL_WIDTH = globals.leftSidebarWidth - 100;
|
|||||||
const ANNO_BUTTON_WIDTH = 50;
|
const ANNO_BUTTON_WIDTH = 50;
|
||||||
const LABEL_WIDTH_ANNO = LABEL_WIDTH - ANNO_BUTTON_WIDTH;
|
const LABEL_WIDTH_ANNO = LABEL_WIDTH - ANNO_BUTTON_WIDTH;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state, ownProps) => {
|
@connect((state, ownProps) => {
|
||||||
const schema = state.annoMatrix?.schema;
|
const schema = (state as any).annoMatrix?.schema;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
const { metadataField } = ownProps;
|
const { metadataField } = ownProps;
|
||||||
const isUserAnno = schema?.annotations?.obsByName[metadataField]?.writable;
|
const isUserAnno = schema?.annotations?.obsByName[metadataField]?.writable;
|
||||||
const categoricalSelection = state.categoricalSelection?.[metadataField];
|
const categoricalSelection = (state as any).categoricalSelection?.[
|
||||||
|
metadataField
|
||||||
|
];
|
||||||
return {
|
return {
|
||||||
colors: state.colors,
|
colors: (state as any).colors,
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: (state as any).annoMatrix,
|
||||||
schema,
|
schema,
|
||||||
crossfilter: state.obsCrossfilter,
|
crossfilter: (state as any).obsCrossfilter,
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
genesets: state.genesets.genesets,
|
genesets: (state as any).genesets.genesets,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class Category extends React.PureComponent {
|
class Category extends React.PureComponent {
|
||||||
static getSelectionState(
|
static getSelectionState(
|
||||||
categoricalSelection,
|
categoricalSelection: any,
|
||||||
metadataField,
|
// @ts-expect-error ts-migrate(6133) FIXME: 'metadataField' is declared but its value is never... Remove this comment to see the full error message
|
||||||
categorySummary
|
metadataField: any,
|
||||||
|
categorySummary: any
|
||||||
) {
|
) {
|
||||||
// total number of categories in this dimension
|
// total number of categories in this dimension
|
||||||
const totalCatCount = categorySummary.numCategoryValues;
|
const totalCatCount = categorySummary.numCategoryValues;
|
||||||
// number of selected options in this category
|
// number of selected options in this category
|
||||||
const selectedCatCount = categorySummary.categoryValues.reduce(
|
const selectedCatCount = categorySummary.categoryValues.reduce(
|
||||||
(res, label) => (categoricalSelection.get(label) ?? true ? res + 1 : res),
|
(res: any, label: any) =>
|
||||||
|
categoricalSelection.get(label) ?? true ? res + 1 : res,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
return selectedCatCount === totalCatCount
|
return selectedCatCount === totalCatCount
|
||||||
@@ -67,13 +73,14 @@ class Category extends React.PureComponent {
|
|||||||
: "some";
|
: "some";
|
||||||
}
|
}
|
||||||
|
|
||||||
static watchAsync(props, prevProps) {
|
static watchAsync(props: any, prevProps: any) {
|
||||||
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
createCategorySummaryFromDfCol = memoize(createCategorySummaryFromDfCol);
|
createCategorySummaryFromDfCol = memoize(createCategorySummaryFromDfCol);
|
||||||
|
|
||||||
getSelectionState(categorySummary) {
|
getSelectionState(categorySummary: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoricalSelection' does not exist on ... Remove this comment to see the full error message
|
||||||
const { categoricalSelection, metadataField } = this.props;
|
const { categoricalSelection, metadataField } = this.props;
|
||||||
return Category.getSelectionState(
|
return Category.getSelectionState(
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
@@ -83,6 +90,7 @@ class Category extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleColorChange = () => {
|
handleColorChange = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "color by categorical metadata",
|
type: "color by categorical metadata",
|
||||||
@@ -91,6 +99,7 @@ class Category extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleCategoryClick = () => {
|
handleCategoryClick = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annotations' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
const { annotations, metadataField, onExpansionChange } = this.props;
|
const { annotations, metadataField, onExpansionChange } = this.props;
|
||||||
const editingCategory =
|
const editingCategory =
|
||||||
annotations.isEditingCategoryName &&
|
annotations.isEditingCategoryName &&
|
||||||
@@ -100,13 +109,13 @@ class Category extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCategoryKeyPress = (e) => {
|
handleCategoryKeyPress = (e: any) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
this.handleCategoryClick();
|
this.handleCategoryClick();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleToggleAllClick = (categorySummary) => {
|
handleToggleAllClick = (categorySummary: any) => {
|
||||||
const isChecked = this.getSelectionState(categorySummary);
|
const isChecked = this.getSelectionState(categorySummary);
|
||||||
if (isChecked === "all") {
|
if (isChecked === "all") {
|
||||||
this.toggleNone(categorySummary);
|
this.toggleNone(categorySummary);
|
||||||
@@ -115,8 +124,9 @@ class Category extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchAsyncProps = async (props) => {
|
fetchAsyncProps = async (props: any) => {
|
||||||
const { annoMatrix, metadataField, colors } = props.watchProps;
|
const { annoMatrix, metadataField, colors } = props.watchProps;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'crossfilter' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
const { crossfilter } = this.props;
|
const { crossfilter } = this.props;
|
||||||
|
|
||||||
const [categoryData, categorySummary, colorData] = await this.fetchData(
|
const [categoryData, categorySummary, colorData] = await this.fetchData(
|
||||||
@@ -136,13 +146,14 @@ class Category extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
async fetchData(annoMatrix, metadataField, colors) {
|
async fetchData(annoMatrix: any, metadataField: any, colors: any) {
|
||||||
/*
|
/*
|
||||||
fetch our data and the color-by data if appropriate, and then build a summary
|
fetch our data and the color-by data if appropriate, and then build a summary
|
||||||
of our category and a color table for the color-by annotation.
|
of our category and a color table for the color-by annotation.
|
||||||
*/
|
*/
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorAccessor, colorMode } = colors;
|
const { colorAccessor, colorMode } = colors;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'genesets' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { genesets } = this.props;
|
const { genesets } = this.props;
|
||||||
let colorDataPromise = Promise.resolve(null);
|
let colorDataPromise = Promise.resolve(null);
|
||||||
if (colorAccessor) {
|
if (colorAccessor) {
|
||||||
@@ -169,8 +180,9 @@ class Category extends React.PureComponent {
|
|||||||
return [categoryData, categorySummary, colorData];
|
return [categoryData, categorySummary, colorData];
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColorTable(colorData) {
|
updateColorTable(colorData: any) {
|
||||||
// color table, which may be null
|
// color table, which may be null
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
const { schema, colors, metadataField } = this.props;
|
const { schema, colors, metadataField } = this.props;
|
||||||
const { colorAccessor, userColors, colorMode } = colors;
|
const { colorAccessor, userColors, colorMode } = colors;
|
||||||
return {
|
return {
|
||||||
@@ -187,7 +199,8 @@ class Category extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleNone(categorySummary) {
|
toggleNone(categorySummary: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.selectCategoricalAllMetadataAction(
|
actions.selectCategoricalAllMetadataAction(
|
||||||
@@ -199,7 +212,8 @@ class Category extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleAll(categorySummary) {
|
toggleAll(categorySummary: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, metadataField } = this.props;
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.selectCategoricalAllMetadataAction(
|
actions.selectCategoricalAllMetadataAction(
|
||||||
@@ -213,12 +227,19 @@ class Category extends React.PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isExpanded' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
isExpanded,
|
isExpanded,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoricalSelection' does not exist on ... Remove this comment to see the full error message
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'crossfilter' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
crossfilter,
|
crossfilter,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colors' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
colors,
|
colors,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
annoMatrix,
|
annoMatrix,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -250,18 +271,26 @@ class Category extends React.PureComponent {
|
|||||||
<Async.Fulfilled persist>
|
<Async.Fulfilled persist>
|
||||||
{(asyncProps) => {
|
{(asyncProps) => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'u... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'unkn... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'unkno... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'un... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleCategoryToggleAllClick' does not e... Remove this comment to see the full error message
|
||||||
handleCategoryToggleAllClick,
|
handleCategoryToggleAllClick,
|
||||||
} = asyncProps;
|
} = asyncProps;
|
||||||
const isTruncated = !!categorySummary?.isTruncated;
|
const isTruncated = !!categorySummary?.isTruncated;
|
||||||
const selectionState = this.getSelectionState(categorySummary);
|
const selectionState = this.getSelectionState(categorySummary);
|
||||||
return (
|
return (
|
||||||
<CategoryRender
|
<CategoryRender
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ metadataField: any; checkboxID: string; is... Remove this comment to see the full error message
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
checkboxID={checkboxID}
|
checkboxID={checkboxID}
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
@@ -290,7 +319,7 @@ class Category extends React.PureComponent {
|
|||||||
|
|
||||||
export default Category;
|
export default Category;
|
||||||
|
|
||||||
const StillLoading = ({ metadataField, checkboxID }) => {
|
const StillLoading = ({ metadataField, checkboxID }: any) => {
|
||||||
/*
|
/*
|
||||||
We are still loading this category, so render a "busy" signal.
|
We are still loading this category, so render a "busy" signal.
|
||||||
*/
|
*/
|
||||||
@@ -341,7 +370,7 @@ const StillLoading = ({ metadataField, checkboxID }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ErrorLoading = ({ metadataField, error }) => {
|
const ErrorLoading = ({ metadataField, error }: any) => {
|
||||||
console.error(error); // log error to console as it is unexpected.
|
console.error(error); // log error to console as it is unexpected.
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: 10, marginTop: 4 }}>
|
<div style={{ marginBottom: 10, marginTop: 4 }}>
|
||||||
@@ -361,16 +390,27 @@ const ErrorLoading = ({ metadataField, error }) => {
|
|||||||
|
|
||||||
const CategoryHeader = React.memo(
|
const CategoryHeader = React.memo(
|
||||||
({
|
({
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'checkboxID' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
checkboxID,
|
checkboxID,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isTruncated' does not exist on type '{ c... Remove this comment to see the full error message
|
||||||
isTruncated,
|
isTruncated,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isExpanded' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
isExpanded,
|
isExpanded,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selectionState' does not exist on type '... Remove this comment to see the full error message
|
||||||
selectionState,
|
selectionState,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onColorChangeClick' does not exist on ty... Remove this comment to see the full error message
|
||||||
onColorChangeClick,
|
onColorChangeClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryMenuClick' does not exist on t... Remove this comment to see the full error message
|
||||||
onCategoryMenuClick,
|
onCategoryMenuClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryMenuKeyPress' does not exist o... Remove this comment to see the full error message
|
||||||
onCategoryMenuKeyPress,
|
onCategoryMenuKeyPress,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryToggleAllClick' does not exist... Remove this comment to see the full error message
|
||||||
onCategoryToggleAllClick,
|
onCategoryToggleAllClick,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
@@ -379,6 +419,7 @@ const CategoryHeader = React.memo(
|
|||||||
const checkboxRef = useRef(null);
|
const checkboxRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
checkboxRef.current.indeterminate = selectionState === "some";
|
checkboxRef.current.indeterminate = selectionState === "some";
|
||||||
}, [checkboxRef.current, selectionState]);
|
}, [checkboxRef.current, selectionState]);
|
||||||
|
|
||||||
@@ -408,6 +449,7 @@ const CategoryHeader = React.memo(
|
|||||||
</label>
|
</label>
|
||||||
<span
|
<span
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'number | ... Remove this comment to see the full error message
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
data-testclass="category-expand"
|
data-testclass="category-expand"
|
||||||
data-testid={`${metadataField}:category-expand`}
|
data-testid={`${metadataField}:category-expand`}
|
||||||
@@ -423,6 +465,7 @@ const CategoryHeader = React.memo(
|
|||||||
maxWidth: isUserAnno ? LABEL_WIDTH_ANNO : LABEL_WIDTH,
|
maxWidth: isUserAnno ? LABEL_WIDTH_ANNO : LABEL_WIDTH,
|
||||||
}}
|
}}
|
||||||
data-testid={`${metadataField}:category-label`}
|
data-testid={`${metadataField}:category-label`}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'number | ... Remove this comment to see the full error message
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
>
|
>
|
||||||
{metadataField}
|
{metadataField}
|
||||||
@@ -441,10 +484,13 @@ const CategoryHeader = React.memo(
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{<AnnoDialogEditCategoryName metadataField={metadataField} />}
|
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ metadataField: any; }' is not assignable t... Remove this comment to see the full error message */}
|
||||||
{<AnnoDialogAddLabel metadataField={metadataField} />}
|
<AnnoDialogEditCategoryName metadataField={metadataField} />
|
||||||
|
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ metadataField: any; }' is not assignable t... Remove this comment to see the full error message */}
|
||||||
|
<AnnoDialogAddLabel metadataField={metadataField} />
|
||||||
<div>
|
<div>
|
||||||
<AnnoMenu
|
<AnnoMenu
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ metadataField: any; isUserAnno: any; creat... Remove this comment to see the full error message
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
createText="Add a new label to this category"
|
createText="Add a new label to this category"
|
||||||
@@ -484,21 +530,37 @@ const CategoryHeader = React.memo(
|
|||||||
|
|
||||||
const CategoryRender = React.memo(
|
const CategoryRender = React.memo(
|
||||||
({
|
({
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'checkboxID' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
checkboxID,
|
checkboxID,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isTruncated' does not exist on type '{ c... Remove this comment to see the full error message
|
||||||
isTruncated,
|
isTruncated,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isExpanded' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
isExpanded,
|
isExpanded,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selectionState' does not exist on type '... Remove this comment to see the full error message
|
||||||
selectionState,
|
selectionState,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type '{ ... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type '{... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type '{ chi... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onColorChangeClick' does not exist on ty... Remove this comment to see the full error message
|
||||||
onColorChangeClick,
|
onColorChangeClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryMenuClick' does not exist on t... Remove this comment to see the full error message
|
||||||
onCategoryMenuClick,
|
onCategoryMenuClick,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryMenuKeyPress' does not exist o... Remove this comment to see the full error message
|
||||||
onCategoryMenuKeyPress,
|
onCategoryMenuKeyPress,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCategoryToggleAllClick' does not exist... Remove this comment to see the full error message
|
||||||
onCategoryToggleAllClick,
|
onCategoryToggleAllClick,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
@@ -533,6 +595,7 @@ const CategoryRender = React.memo(
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CategoryHeader
|
<CategoryHeader
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ metadataField: any; checkboxID: any; isUse... Remove this comment to see the full error message
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
checkboxID={checkboxID}
|
checkboxID={checkboxID}
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
@@ -551,6 +614,7 @@ const CategoryRender = React.memo(
|
|||||||
/* values*/
|
/* values*/
|
||||||
isExpanded ? (
|
isExpanded ? (
|
||||||
<CategoryValueList
|
<CategoryValueList
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isUserAnno: any; metadataField: any; categ... Remove this comment to see the full error message
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
categoryData={categoryData}
|
categoryData={categoryData}
|
||||||
@@ -574,12 +638,19 @@ const CategoryRender = React.memo(
|
|||||||
|
|
||||||
const CategoryValueList = React.memo(
|
const CategoryValueList = React.memo(
|
||||||
({
|
({
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type '{ ... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type '{... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type '{ chi... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type '{ ch... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
}) => {
|
}) => {
|
||||||
const tuples = [...categorySummary.categoryValueIndices];
|
const tuples = [...categorySummary.categoryValueIndices];
|
||||||
@@ -594,6 +665,7 @@ const CategoryValueList = React.memo(
|
|||||||
{tuples.map(([value, index]) => (
|
{tuples.map(([value, index]) => (
|
||||||
<Value
|
<Value
|
||||||
key={value}
|
key={value}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ key: any; isUserAnno: any; metadataField: ... Remove this comment to see the full error message
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
categoryIndex={index}
|
categoryIndex={index}
|
||||||
@@ -615,6 +687,7 @@ const CategoryValueList = React.memo(
|
|||||||
{tuples.map(([value, index]) => (
|
{tuples.map(([value, index]) => (
|
||||||
<Flipped key={value} flipId={value}>
|
<Flipped key={value} flipId={value}>
|
||||||
<Value
|
<Value
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isUserAnno: any; metadataField: any; categ... Remove this comment to see the full error message
|
||||||
isUserAnno={isUserAnno}
|
isUserAnno={isUserAnno}
|
||||||
metadataField={metadataField}
|
metadataField={metadataField}
|
||||||
categoryIndex={index}
|
categoryIndex={index}
|
||||||
+37
-32
@@ -10,13 +10,17 @@ import LabelInput from "../labelInput";
|
|||||||
import { labelPrompt } from "./labelUtil";
|
import { labelPrompt } from "./labelUtil";
|
||||||
import actions from "../../actions";
|
import actions from "../../actions";
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
writableCategoriesEnabled:
|
||||||
schema: state.annoMatrix?.schema,
|
(state as any).config?.parameters?.annotations ?? false,
|
||||||
userInfo: state.userInfo,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
|
userInfo: (state as any).userInfo,
|
||||||
}))
|
}))
|
||||||
class Categories extends React.Component {
|
class Categories extends React.Component<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
createAnnoModeActive: false,
|
createAnnoModeActive: false,
|
||||||
@@ -26,7 +30,8 @@ class Categories extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCreateUserAnno = (e) => {
|
handleCreateUserAnno = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { newCategoryText, categoryToDuplicate } = this.state;
|
const { newCategoryText, categoryToDuplicate } = this.state;
|
||||||
dispatch(
|
dispatch(
|
||||||
@@ -55,50 +60,48 @@ class Categories extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleModalDuplicateCategorySelection = (d) => {
|
handleModalDuplicateCategorySelection = (d: any) => {
|
||||||
this.setState({ categoryToDuplicate: d });
|
this.setState({ categoryToDuplicate: d });
|
||||||
};
|
};
|
||||||
|
|
||||||
categoryNameError = (name) => {
|
categoryNameError = (name: any) => {
|
||||||
/*
|
/*
|
||||||
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
||||||
or return an error type.
|
or return an error type.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* allow empty string */
|
/* allow empty string */
|
||||||
if (name === "") return false;
|
if (name === "") return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
test for uniqueness against *all* annotation names, not just the subset
|
test for uniqueness against *all* annotation names, not just the subset
|
||||||
we render as categorical.
|
we render as categorical.
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
const { schema } = this.props;
|
const { schema } = this.props;
|
||||||
const allCategoryNames = schema.annotations.obs.columns.map((c) => c.name);
|
const allCategoryNames = schema.annotations.obs.columns.map(
|
||||||
|
(c: any) => c.name
|
||||||
|
);
|
||||||
/* check category name syntax */
|
/* check category name syntax */
|
||||||
const error = AnnotationsHelpers.annotationNameIsErroneous(name);
|
const error = AnnotationsHelpers.annotationNameIsErroneous(name);
|
||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disallow duplicates */
|
/* disallow duplicates */
|
||||||
if (allCategoryNames.indexOf(name) !== -1) {
|
if (allCategoryNames.indexOf(name) !== -1) {
|
||||||
return "duplicate";
|
return "duplicate";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise, no error */
|
/* otherwise, no error */
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (name) => {
|
handleChange = (name: any) => {
|
||||||
this.setState({ newCategoryText: name });
|
this.setState({ newCategoryText: name });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSelect = (name) => {
|
handleSelect = (name: any) => {
|
||||||
this.setState({ newCategoryText: name });
|
this.setState({ newCategoryText: name });
|
||||||
};
|
};
|
||||||
|
|
||||||
instruction = (name) => {
|
instruction = (name: any) => {
|
||||||
return labelPrompt(
|
return labelPrompt(
|
||||||
this.categoryNameError(name),
|
this.categoryNameError(name),
|
||||||
"New, unique category name",
|
"New, unique category name",
|
||||||
@@ -106,7 +109,7 @@ class Categories extends React.Component {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
onExpansionChange = (catName) => {
|
onExpansionChange = (catName: any) => {
|
||||||
const { expandedCats } = this.state;
|
const { expandedCats } = this.state;
|
||||||
if (expandedCats.has(catName)) {
|
if (expandedCats.has(catName)) {
|
||||||
const _expandedCats = new Set(expandedCats);
|
const _expandedCats = new Set(expandedCats);
|
||||||
@@ -126,16 +129,13 @@ class Categories extends React.Component {
|
|||||||
newCategoryText,
|
newCategoryText,
|
||||||
expandedCats,
|
expandedCats,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const {
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'writableCategoriesEnabled' does not exis... Remove this comment to see the full error message
|
||||||
writableCategoriesEnabled,
|
const { writableCategoriesEnabled, schema, userInfo } = this.props;
|
||||||
schema,
|
|
||||||
userInfo,
|
|
||||||
} = this.props;
|
|
||||||
/* all names, sorted in display order. Will be rendered in this order */
|
/* all names, sorted in display order. Will be rendered in this order */
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||||
const allCategoryNames = ControlsHelpers.selectableCategoryNames(
|
const allCategoryNames = ControlsHelpers.selectableCategoryNames(
|
||||||
schema
|
schema
|
||||||
).sort();
|
).sort();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -143,6 +143,7 @@ class Categories extends React.Component {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AnnoDialog
|
<AnnoDialog
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isActive: any; title: string; instruction:... Remove this comment to see the full error message
|
||||||
isActive={createAnnoModeActive}
|
isActive={createAnnoModeActive}
|
||||||
title="Create new category"
|
title="Create new category"
|
||||||
instruction={this.instruction(newCategoryText)}
|
instruction={this.instruction(newCategoryText)}
|
||||||
@@ -155,6 +156,7 @@ class Categories extends React.Component {
|
|||||||
handleCancel={this.handleDisableAnnoMode}
|
handleCancel={this.handleDisableAnnoMode}
|
||||||
annoInput={
|
annoInput={
|
||||||
<LabelInput
|
<LabelInput
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ labelSuggestions: null; onChange: (name: a... Remove this comment to see the full error message
|
||||||
labelSuggestions={null}
|
labelSuggestions={null}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onSelect={this.handleSelect}
|
onSelect={this.handleSelect}
|
||||||
@@ -169,6 +171,7 @@ class Categories extends React.Component {
|
|||||||
}
|
}
|
||||||
annoSelect={
|
annoSelect={
|
||||||
<AnnoSelect
|
<AnnoSelect
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ handleModalDuplicateCategorySelection: (d:... Remove this comment to see the full error message
|
||||||
handleModalDuplicateCategorySelection={
|
handleModalDuplicateCategorySelection={
|
||||||
this.handleModalDuplicateCategorySelection
|
this.handleModalDuplicateCategorySelection
|
||||||
}
|
}
|
||||||
@@ -209,12 +212,13 @@ class Categories extends React.Component {
|
|||||||
|
|
||||||
{/* READ ONLY CATEGORICAL FIELDS */}
|
{/* READ ONLY CATEGORICAL FIELDS */}
|
||||||
{/* this is duplicative but flat, could be abstracted */}
|
{/* this is duplicative but flat, could be abstracted */}
|
||||||
{allCategoryNames.map((catName) =>
|
{allCategoryNames.map((catName: any) =>
|
||||||
!schema.annotations.obsByName[catName].writable &&
|
!schema.annotations.obsByName[catName].writable &&
|
||||||
(schema.annotations.obsByName[catName].categories?.length > 1 ||
|
(schema.annotations.obsByName[catName].categories?.length > 1 ||
|
||||||
!schema.annotations.obsByName[catName].categories) ? (
|
!schema.annotations.obsByName[catName].categories) ? (
|
||||||
<Category
|
<Category
|
||||||
key={catName}
|
key={catName}
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
metadataField={catName}
|
metadataField={catName}
|
||||||
onExpansionChange={this.onExpansionChange}
|
onExpansionChange={this.onExpansionChange}
|
||||||
isExpanded={expandedCats.has(catName)}
|
isExpanded={expandedCats.has(catName)}
|
||||||
@@ -223,10 +227,11 @@ class Categories extends React.Component {
|
|||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
{/* WRITEABLE FIELDS */}
|
{/* WRITEABLE FIELDS */}
|
||||||
{allCategoryNames.map((catName) =>
|
{allCategoryNames.map((catName: any) =>
|
||||||
schema.annotations.obsByName[catName].writable ? (
|
schema.annotations.obsByName[catName].writable ? (
|
||||||
<Category
|
<Category
|
||||||
key={catName}
|
key={catName}
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
metadataField={catName}
|
metadataField={catName}
|
||||||
onExpansionChange={this.onExpansionChange}
|
onExpansionChange={this.onExpansionChange}
|
||||||
isExpanded={expandedCats.has(catName)}
|
isExpanded={expandedCats.has(catName)}
|
||||||
+3
-2
@@ -3,7 +3,7 @@ import { Colors } from "@blueprintjs/core";
|
|||||||
|
|
||||||
import { AnnotationsHelpers } from "../../util/stateManager";
|
import { AnnotationsHelpers } from "../../util/stateManager";
|
||||||
|
|
||||||
export function isLabelErroneous(label, metadataField, schema) {
|
export function isLabelErroneous(label: any, metadataField: any, schema: any) {
|
||||||
/*
|
/*
|
||||||
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
||||||
or return an error type.
|
or return an error type.
|
||||||
@@ -35,9 +35,10 @@ const errorMessageMap = {
|
|||||||
"multi-space-run": "Multiple consecutive spaces not allowed",
|
"multi-space-run": "Multiple consecutive spaces not allowed",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function labelPrompt(err, prolog, epilog) {
|
export function labelPrompt(err: any, prolog: any, epilog: any) {
|
||||||
let errPrompt = null;
|
let errPrompt = null;
|
||||||
if (err) {
|
if (err) {
|
||||||
|
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||||
let errMsg = errorMessageMap[err] ?? "error";
|
let errMsg = errorMessageMap[err] ?? "error";
|
||||||
errMsg = errMsg[0].toLowerCase() + errMsg.slice(1);
|
errMsg = errMsg[0].toLowerCase() + errMsg.slice(1);
|
||||||
errPrompt = (
|
errPrompt = (
|
||||||
+96
-36
@@ -13,6 +13,7 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
import * as globals from "../../../globals";
|
import * as globals from "../../../globals";
|
||||||
|
// @ts-expect-error ts-migrate(2307) FIXME: Cannot find module '../categorical.css' or its cor... Remove this comment to see the full error message
|
||||||
import styles from "../categorical.css";
|
import styles from "../categorical.css";
|
||||||
import AnnoDialog from "../../annoDialog";
|
import AnnoDialog from "../../annoDialog";
|
||||||
import LabelInput from "../../labelInput";
|
import LabelInput from "../../labelInput";
|
||||||
@@ -29,15 +30,20 @@ const STACKED_BAR_HEIGHT = 11;
|
|||||||
const STACKED_BAR_WIDTH = 100;
|
const STACKED_BAR_WIDTH = 100;
|
||||||
|
|
||||||
/* this is defined outside of the class so we can use it in connect() */
|
/* this is defined outside of the class so we can use it in connect() */
|
||||||
function _currentLabelAsString(ownProps) {
|
function _currentLabelAsString(ownProps: any) {
|
||||||
const { label } = ownProps;
|
const { label } = ownProps;
|
||||||
// when called as a function, the String() constructor performs type conversion,
|
// when called as a function, the String() constructor performs type conversion,
|
||||||
// and returns a primitive string.
|
// and returns a primitive string.
|
||||||
return String(label);
|
return String(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state, ownProps) => {
|
@connect((state, ownProps) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'pointDilation' does not exist on type 'D... Remove this comment to see the full error message
|
||||||
const { pointDilation, categoricalSelection } = state;
|
const { pointDilation, categoricalSelection } = state;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type '{... Remove this comment to see the full error message
|
||||||
const { metadataField, categorySummary, categoryIndex } = ownProps;
|
const { metadataField, categorySummary, categoryIndex } = ownProps;
|
||||||
const isDilated =
|
const isDilated =
|
||||||
pointDilation.metadataField === metadataField &&
|
pointDilation.metadataField === metadataField &&
|
||||||
@@ -48,27 +54,28 @@ function _currentLabelAsString(ownProps) {
|
|||||||
const isSelected = category.get(label) ?? true;
|
const isSelected = category.get(label) ?? true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
annotations: state.annotations,
|
annotations: (state as any).annotations,
|
||||||
schema: state.annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
isDilated,
|
isDilated,
|
||||||
isSelected,
|
isSelected,
|
||||||
label,
|
label,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class CategoryValue extends React.Component {
|
class CategoryValue extends React.Component<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
editedLabelText: this.currentLabelAsString(),
|
editedLabelText: this.currentLabelAsString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: {}) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField, categoryIndex, categorySummary } = this.props;
|
const { metadataField, categoryIndex, categorySummary } = this.props;
|
||||||
if (
|
if (
|
||||||
prevProps.metadataField !== metadataField ||
|
(prevProps as any).metadataField !== metadataField ||
|
||||||
prevProps.categoryIndex !== categoryIndex ||
|
(prevProps as any).categoryIndex !== categoryIndex ||
|
||||||
prevProps.categorySummary !== categorySummary
|
(prevProps as any).categorySummary !== categorySummary
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line react/no-did-update-set-state --- adequately checked to prevent looping
|
// eslint-disable-next-line react/no-did-update-set-state --- adequately checked to prevent looping
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -79,22 +86,26 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
// If coloring by and this isn't the colorAccessor and it isn't being edited
|
// If coloring by and this isn't the colorAccessor and it isn't being edited
|
||||||
get shouldRenderStackedBarOrHistogram() {
|
get shouldRenderStackedBarOrHistogram() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { colorAccessor, isColorBy, annotations } = this.props;
|
const { colorAccessor, isColorBy, annotations } = this.props;
|
||||||
|
|
||||||
return !!colorAccessor && !isColorBy && !annotations.isEditingLabelName;
|
return !!colorAccessor && !isColorBy && !annotations.isEditingLabelName;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteValue = () => {
|
handleDeleteValue = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, label } = this.props;
|
const { dispatch, metadataField, label } = this.props;
|
||||||
dispatch(actions.annotationDeleteLabelFromCategory(metadataField, label));
|
dispatch(actions.annotationDeleteLabelFromCategory(metadataField, label));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAddCurrentSelectionToThisLabel = () => {
|
handleAddCurrentSelectionToThisLabel = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, label } = this.props;
|
const { dispatch, metadataField, label } = this.props;
|
||||||
dispatch(actions.annotationLabelCurrentSelection(metadataField, label));
|
dispatch(actions.annotationLabelCurrentSelection(metadataField, label));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEditValue = (e) => {
|
handleEditValue = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, label } = this.props;
|
const { dispatch, metadataField, label } = this.props;
|
||||||
const { editedLabelText } = this.state;
|
const { editedLabelText } = this.state;
|
||||||
this.cancelEditMode();
|
this.cancelEditMode();
|
||||||
@@ -108,7 +119,8 @@ class CategoryValue extends React.Component {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCreateArbitraryLabel = (txt) => {
|
handleCreateArbitraryLabel = (txt: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, label } = this.props;
|
const { dispatch, metadataField, label } = this.props;
|
||||||
this.cancelEditMode();
|
this.cancelEditMode();
|
||||||
dispatch(
|
dispatch(
|
||||||
@@ -116,17 +128,19 @@ class CategoryValue extends React.Component {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
labelNameError = (name) => {
|
labelNameError = (name: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { metadataField, schema } = this.props;
|
const { metadataField, schema } = this.props;
|
||||||
if (name === this.currentLabelAsString()) return false;
|
if (name === this.currentLabelAsString()) return false;
|
||||||
return isLabelErroneous(name, metadataField, schema);
|
return isLabelErroneous(name, metadataField, schema);
|
||||||
};
|
};
|
||||||
|
|
||||||
instruction = (label) => {
|
instruction = (label: any) => {
|
||||||
return labelPrompt(this.labelNameError(label), "New, unique label", ":");
|
return labelPrompt(this.labelNameError(label), "New, unique label", ":");
|
||||||
};
|
};
|
||||||
|
|
||||||
activateEditLabelMode = () => {
|
activateEditLabelMode = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "annotation: activate edit label mode",
|
type: "annotation: activate edit label mode",
|
||||||
@@ -137,6 +151,7 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
cancelEditMode = () => {
|
cancelEditMode = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
||||||
this.setState({
|
this.setState({
|
||||||
editedLabelText: this.currentLabelAsString(),
|
editedLabelText: this.currentLabelAsString(),
|
||||||
@@ -151,9 +166,13 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
toggleOff = () => {
|
toggleOff = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryIndex' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
categoryIndex,
|
categoryIndex,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const label = categorySummary.categoryValues[categoryIndex];
|
const label = categorySummary.categoryValues[categoryIndex];
|
||||||
@@ -168,7 +187,7 @@ class CategoryValue extends React.Component {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate = (nextProps, nextState) => {
|
shouldComponentUpdate = (nextProps: any, nextState: any) => {
|
||||||
/*
|
/*
|
||||||
Checks to see if at least one of the following changed:
|
Checks to see if at least one of the following changed:
|
||||||
* world state
|
* world state
|
||||||
@@ -179,6 +198,7 @@ class CategoryValue extends React.Component {
|
|||||||
If and only if true, update the component
|
If and only if true, update the component
|
||||||
*/
|
*/
|
||||||
const { props, state } = this;
|
const { props, state } = this;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryIndex' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { categoryIndex, categorySummary, isSelected } = props;
|
const { categoryIndex, categorySummary, isSelected } = props;
|
||||||
const {
|
const {
|
||||||
categoryIndex: newCategoryIndex,
|
categoryIndex: newCategoryIndex,
|
||||||
@@ -191,10 +211,12 @@ class CategoryValue extends React.Component {
|
|||||||
const labelChanged = label !== newLabel;
|
const labelChanged = label !== newLabel;
|
||||||
const valueSelectionChange = isSelected !== newIsSelected;
|
const valueSelectionChange = isSelected !== newIsSelected;
|
||||||
|
|
||||||
const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor;
|
const colorAccessorChange =
|
||||||
const annotationsChange = props.annotations !== nextProps.annotations;
|
(props as any).colorAccessor !== nextProps.colorAccessor;
|
||||||
|
const annotationsChange =
|
||||||
|
(props as any).annotations !== nextProps.annotations;
|
||||||
const editingLabel = state.editedLabelText !== nextState.editedLabelText;
|
const editingLabel = state.editedLabelText !== nextState.editedLabelText;
|
||||||
const dilationChange = props.isDilated !== nextProps.isDilated;
|
const dilationChange = (props as any).isDilated !== nextProps.isDilated;
|
||||||
|
|
||||||
const count = categorySummary.categoryValueCounts[categoryIndex];
|
const count = categorySummary.categoryValueCounts[categoryIndex];
|
||||||
const newCount = newCategorySummary.categoryValueCounts[newCategoryIndex];
|
const newCount = newCategorySummary.categoryValueCounts[newCategoryIndex];
|
||||||
@@ -205,7 +227,7 @@ class CategoryValue extends React.Component {
|
|||||||
// if any one changes, but only for the currently colored-by category.
|
// if any one changes, but only for the currently colored-by category.
|
||||||
const colorMightHaveChanged =
|
const colorMightHaveChanged =
|
||||||
nextProps.colorAccessor === nextProps.metadataField &&
|
nextProps.colorAccessor === nextProps.metadataField &&
|
||||||
props.categorySummary !== nextProps.categorySummary;
|
(props as any).categorySummary !== nextProps.categorySummary;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
labelChanged ||
|
labelChanged ||
|
||||||
@@ -221,9 +243,13 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
toggleOn = () => {
|
toggleOn = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
dispatch,
|
dispatch,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryIndex' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
categoryIndex,
|
categoryIndex,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const label = categorySummary.categoryValues[categoryIndex];
|
const label = categorySummary.categoryValues[categoryIndex];
|
||||||
@@ -239,6 +265,7 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleMouseEnter = () => {
|
handleMouseEnter = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "category value mouse hover start",
|
type: "category value mouse hover start",
|
||||||
@@ -249,6 +276,7 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleMouseExit = () => {
|
handleMouseExit = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
const { dispatch, metadataField, categoryIndex, label } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "category value mouse hover end",
|
type: "category value mouse hover end",
|
||||||
@@ -258,23 +286,24 @@ class CategoryValue extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleTextChange = (text) => {
|
handleTextChange = (text: any) => {
|
||||||
this.setState({ editedLabelText: text });
|
this.setState({ editedLabelText: text });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChoice = (e) => {
|
handleChoice = (e: any) => {
|
||||||
/* Blueprint Suggest format */
|
/* Blueprint Suggest format */
|
||||||
this.setState({ editedLabelText: e.target });
|
this.setState({ editedLabelText: e.target });
|
||||||
};
|
};
|
||||||
|
|
||||||
createHistogramBins = (
|
createHistogramBins = (
|
||||||
metadataField,
|
metadataField: any,
|
||||||
categoryData,
|
categoryData: any,
|
||||||
colorAccessor,
|
// @ts-expect-error ts-migrate(6133) FIXME: 'colorAccessor' is declared but its value is never... Remove this comment to see the full error message
|
||||||
colorData,
|
colorAccessor: any,
|
||||||
categoryValue,
|
colorData: any,
|
||||||
width,
|
categoryValue: any,
|
||||||
height
|
width: any,
|
||||||
|
height: any
|
||||||
) => {
|
) => {
|
||||||
/*
|
/*
|
||||||
Knowing that colorScale is based off continuous data,
|
Knowing that colorScale is based off continuous data,
|
||||||
@@ -309,14 +338,15 @@ class CategoryValue extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
createStackedGraphBins = (
|
createStackedGraphBins = (
|
||||||
metadataField,
|
metadataField: any,
|
||||||
categoryData,
|
categoryData: any,
|
||||||
colorAccessor,
|
colorAccessor: any,
|
||||||
colorData,
|
colorData: any,
|
||||||
categoryValue,
|
categoryValue: any,
|
||||||
colorTable,
|
// @ts-expect-error ts-migrate(6133) FIXME: 'colorTable' is declared but its value is never re... Remove this comment to see the full error message
|
||||||
schema,
|
colorTable: any,
|
||||||
width
|
schema: any,
|
||||||
|
width: any
|
||||||
) => {
|
) => {
|
||||||
/*
|
/*
|
||||||
Knowing that the color scale is based off of categorical data,
|
Knowing that the color scale is based off of categorical data,
|
||||||
@@ -357,12 +387,13 @@ class CategoryValue extends React.Component {
|
|||||||
return _currentLabelAsString(this.props);
|
return _currentLabelAsString(this.props);
|
||||||
}
|
}
|
||||||
|
|
||||||
isAddCurrentSelectionDisabled(crossfilter, category, value) {
|
isAddCurrentSelectionDisabled(crossfilter: any, category: any, value: any) {
|
||||||
/*
|
/*
|
||||||
disable "add current selection to label", if one of the following is true:
|
disable "add current selection to label", if one of the following is true:
|
||||||
1. no cells are selected
|
1. no cells are selected
|
||||||
2. all currently selected cells already have this label, on this category
|
2. all currently selected cells already have this label, on this category
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
const { categoryData } = this.props;
|
const { categoryData } = this.props;
|
||||||
|
|
||||||
// 1. no cells selected?
|
// 1. no cells selected?
|
||||||
@@ -382,12 +413,19 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
renderMiniStackedBar = () => {
|
renderMiniStackedBar = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
schema,
|
schema,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'label' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
label,
|
label,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const isColorBy = metadataField === colorAccessor;
|
const isColorBy = metadataField === colorAccessor;
|
||||||
@@ -425,6 +463,7 @@ class CategoryValue extends React.Component {
|
|||||||
domain,
|
domain,
|
||||||
occupancy,
|
occupancy,
|
||||||
}}
|
}}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ height: number; width: number; colorTable:... Remove this comment to see the full error message
|
||||||
height={STACKED_BAR_HEIGHT}
|
height={STACKED_BAR_HEIGHT}
|
||||||
width={STACKED_BAR_WIDTH}
|
width={STACKED_BAR_WIDTH}
|
||||||
/>
|
/>
|
||||||
@@ -433,12 +472,19 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
renderMiniHistogram = () => {
|
renderMiniHistogram = () => {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
schema,
|
schema,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'label' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
label,
|
label,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const colorScale = colorTable?.scale;
|
const colorScale = colorTable?.scale;
|
||||||
@@ -473,6 +519,7 @@ class CategoryValue extends React.Component {
|
|||||||
yScale,
|
yScale,
|
||||||
bins,
|
bins,
|
||||||
}}
|
}}
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ obsOrVarContinuousFieldDisplayName: any; d... Remove this comment to see the full error message
|
||||||
obsOrVarContinuousFieldDisplayName={colorAccessor}
|
obsOrVarContinuousFieldDisplayName={colorAccessor}
|
||||||
domainLabel={label}
|
domainLabel={label}
|
||||||
height={STACKED_BAR_HEIGHT}
|
height={STACKED_BAR_HEIGHT}
|
||||||
@@ -483,15 +530,25 @@ class CategoryValue extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryIndex' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
categoryIndex,
|
categoryIndex,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isUserAnno' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annotations' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||||
annotations,
|
annotations,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isDilated' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
isDilated,
|
isDilated,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isSelected' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
isSelected,
|
isSelected,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
|
||||||
categorySummary,
|
categorySummary,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'label' does not exist on type 'Readonly<... Remove this comment to see the full error message
|
||||||
label,
|
label,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const colorScale = colorTable?.scale;
|
const colorScale = colorTable?.scale;
|
||||||
@@ -587,6 +644,7 @@ class CategoryValue extends React.Component {
|
|||||||
<span
|
<span
|
||||||
data-testid={`categorical-value-${metadataField}-${displayString}`}
|
data-testid={`categorical-value-${metadataField}-${displayString}`}
|
||||||
data-testclass="categorical-value"
|
data-testclass="categorical-value"
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'number | ... Remove this comment to see the full error message
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
style={{
|
style={{
|
||||||
width: labelWidth,
|
width: labelWidth,
|
||||||
@@ -612,6 +670,7 @@ class CategoryValue extends React.Component {
|
|||||||
{editModeActive ? (
|
{editModeActive ? (
|
||||||
<div>
|
<div>
|
||||||
<AnnoDialog
|
<AnnoDialog
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isActive: any; inputProps: { "data-testid"... Remove this comment to see the full error message
|
||||||
isActive={editModeActive}
|
isActive={editModeActive}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"data-testid": `${metadataField}:edit-label-name-dialog`,
|
"data-testid": `${metadataField}:edit-label-name-dialog`,
|
||||||
@@ -630,6 +689,7 @@ class CategoryValue extends React.Component {
|
|||||||
handleCancel={this.cancelEditMode}
|
handleCancel={this.cancelEditMode}
|
||||||
annoInput={
|
annoInput={
|
||||||
<LabelInput
|
<LabelInput
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ label: any; labelSuggestions: null; onChan... Remove this comment to see the full error message
|
||||||
label={editedLabelText}
|
label={editedLabelText}
|
||||||
labelSuggestions={null}
|
labelSuggestions={null}
|
||||||
onChange={this.handleTextChange}
|
onChange={this.handleTextChange}
|
||||||
+24
-30
@@ -8,64 +8,59 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
schema: state.annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
}))
|
}))
|
||||||
class Occupancy extends React.PureComponent {
|
class Occupancy extends React.PureComponent {
|
||||||
|
canvas: any;
|
||||||
|
|
||||||
_WIDTH = 100;
|
_WIDTH = 100;
|
||||||
|
|
||||||
_HEIGHT = 11;
|
_HEIGHT = 11;
|
||||||
|
|
||||||
createHistogram = () => {
|
createHistogram = () => {
|
||||||
/*
|
/*
|
||||||
Knowing that colorScale is based off continous data,
|
Knowing that colorScale is based off continous data,
|
||||||
createHistogram fetches the continous data in relation to the cells releveant to the catagory value.
|
createHistogram fetches the continous data in relation to the cells releveant to the catagory value.
|
||||||
It then seperates that data into 50 bins for drawing the mini-histogram
|
It then seperates that data into 50 bins for drawing the mini-histogram
|
||||||
*/
|
*/
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryValue' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
categoryValue,
|
categoryValue,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
|
|
||||||
const groupBy = categoryData.col(metadataField);
|
const groupBy = categoryData.col(metadataField);
|
||||||
const col = colorData.icol(0);
|
const col = colorData.icol(0);
|
||||||
const range = col.summarize();
|
const range = col.summarize();
|
||||||
|
|
||||||
const histogramMap = col.histogram(
|
const histogramMap = col.histogram(
|
||||||
50,
|
50,
|
||||||
[range.min, range.max],
|
[range.min, range.max],
|
||||||
groupBy
|
groupBy
|
||||||
); /* Because the signature changes we really need different names for histogram to differentiate signatures */
|
); /* Because the signature changes we really need different names for histogram to differentiate signatures */
|
||||||
|
|
||||||
const bins = histogramMap.has(categoryValue)
|
const bins = histogramMap.has(categoryValue)
|
||||||
? histogramMap.get(categoryValue)
|
? histogramMap.get(categoryValue)
|
||||||
: new Array(50).fill(0);
|
: new Array(50).fill(0);
|
||||||
|
|
||||||
const xScale = d3
|
const xScale = d3
|
||||||
.scaleLinear()
|
.scaleLinear()
|
||||||
.domain([0, bins.length])
|
.domain([0, bins.length])
|
||||||
.range([0, this._WIDTH]);
|
.range([0, this._WIDTH]);
|
||||||
|
|
||||||
const largestBin = Math.max(...bins);
|
const largestBin = Math.max(...bins);
|
||||||
|
|
||||||
const yScale = d3
|
const yScale = d3
|
||||||
.scaleLinear()
|
.scaleLinear()
|
||||||
.domain([0, largestBin])
|
.domain([0, largestBin])
|
||||||
.range([0, this._HEIGHT]);
|
.range([0, this._HEIGHT]);
|
||||||
|
|
||||||
const ctx = this.canvas.getContext("2d");
|
const ctx = this.canvas.getContext("2d");
|
||||||
|
|
||||||
ctx.fillStyle = "#000";
|
ctx.fillStyle = "#000";
|
||||||
|
|
||||||
let x;
|
let x;
|
||||||
let y;
|
let y;
|
||||||
|
|
||||||
const rectWidth = this._WIDTH / bins.length;
|
const rectWidth = this._WIDTH / bins.length;
|
||||||
|
|
||||||
for (let i = 0, { length } = bins; i < length; i += 1) {
|
for (let i = 0, { length } = bins; i < length; i += 1) {
|
||||||
x = xScale(i);
|
x = xScale(i);
|
||||||
y = yScale(bins[i]);
|
y = yScale(bins[i]);
|
||||||
@@ -75,32 +70,34 @@ class Occupancy extends React.PureComponent {
|
|||||||
|
|
||||||
createOccupancyStack = () => {
|
createOccupancyStack = () => {
|
||||||
/*
|
/*
|
||||||
Knowing that the color scale is based off of catagorical data,
|
Knowing that the color scale is based off of catagorical data,
|
||||||
createOccupancyStack obtains a map showing the number if cells per colored value
|
createOccupancyStack obtains a map showing the number if cells per colored value
|
||||||
Using the colorScale a stack of colored bars is drawn representing the map
|
Using the colorScale a stack of colored bars is drawn representing the map
|
||||||
*/
|
*/
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
metadataField,
|
metadataField,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
categoryData,
|
categoryData,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryValue' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
categoryValue,
|
categoryValue,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
colorTable,
|
colorTable,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
schema,
|
schema,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
colorData,
|
colorData,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { scale: colorScale } = colorTable;
|
const { scale: colorScale } = colorTable;
|
||||||
|
|
||||||
const ctx = this.canvas?.getContext("2d");
|
const ctx = this.canvas?.getContext("2d");
|
||||||
|
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
const groupBy = categoryData.col(metadataField);
|
const groupBy = categoryData.col(metadataField);
|
||||||
const occupancyMap = colorData
|
const occupancyMap = colorData
|
||||||
.col(colorAccessor)
|
.col(colorAccessor)
|
||||||
.histogramCategorical(groupBy);
|
.histogramCategorical(groupBy);
|
||||||
|
|
||||||
const occupancy = occupancyMap.get(categoryValue);
|
const occupancy = occupancyMap.get(categoryValue);
|
||||||
|
|
||||||
if (occupancy && occupancy.size > 0) {
|
if (occupancy && occupancy.size > 0) {
|
||||||
// not all categories have occupancy, so occupancy may be undefined.
|
// not all categories have occupancy, so occupancy may be undefined.
|
||||||
const x = d3
|
const x = d3
|
||||||
@@ -110,15 +107,12 @@ class Occupancy extends React.PureComponent {
|
|||||||
.range([0, this._WIDTH]);
|
.range([0, this._WIDTH]);
|
||||||
const categories =
|
const categories =
|
||||||
schema.annotations.obsByName[colorAccessor]?.categories;
|
schema.annotations.obsByName[colorAccessor]?.categories;
|
||||||
|
|
||||||
let currentOffset = 0;
|
let currentOffset = 0;
|
||||||
const dfColumn = colorData.col(colorAccessor);
|
const dfColumn = colorData.col(colorAccessor);
|
||||||
const categoryValues = dfColumn.summarizeCategorical().categories;
|
const categoryValues = dfColumn.summarizeCategorical().categories;
|
||||||
|
|
||||||
let o;
|
let o;
|
||||||
let scaledValue;
|
let scaledValue;
|
||||||
let value;
|
let value;
|
||||||
|
|
||||||
for (let i = 0, { length } = categoryValues; i < length; i += 1) {
|
for (let i = 0, { length } = categoryValues; i < length; i += 1) {
|
||||||
value = categoryValues[i];
|
value = categoryValues[i];
|
||||||
o = occupancy.get(value);
|
o = occupancy.get(value);
|
||||||
@@ -133,11 +127,11 @@ class Occupancy extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||||
const { colorAccessor, categoryValue, colorByIsCategorical } = this.props;
|
const { colorAccessor, categoryValue, colorByIsCategorical } = this.props;
|
||||||
const { canvas } = this;
|
const { canvas } = this;
|
||||||
if (canvas)
|
if (canvas)
|
||||||
canvas.getContext("2d").clearRect(0, 0, this._WIDTH, this._HEIGHT);
|
canvas.getContext("2d").clearRect(0, 0, this._WIDTH, this._HEIGHT);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
interactionKind={PopoverInteractionKind.HOVER_TARGET_ONLY}
|
interactionKind={PopoverInteractionKind.HOVER_TARGET_ONLY}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/* rc slider https://www.npmjs.com/package/rc-slider */
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import HistogramBrush from "../brushableHistogram";
|
|
||||||
|
|
||||||
@connect((state) => ({
|
|
||||||
schema: state.annoMatrix?.schema,
|
|
||||||
}))
|
|
||||||
class Continuous extends React.PureComponent {
|
|
||||||
render() {
|
|
||||||
/* initial value for iterator to simulate index, ranges is an object */
|
|
||||||
const { schema } = this.props;
|
|
||||||
if (!schema) return null;
|
|
||||||
const obsIndex = schema.annotations.obs.index;
|
|
||||||
const allContinuousNames = schema.annotations.obs.columns
|
|
||||||
.filter((col) => col.type === "int32" || col.type === "float32")
|
|
||||||
.filter((col) => col.name !== obsIndex)
|
|
||||||
.filter((col) => !col.writable) // skip user annotations - they will be treated as categorical
|
|
||||||
.map((col) => col.name);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{allContinuousNames.map((key, zebra) => (
|
|
||||||
<HistogramBrush key={key} field={key} isObs zebra={zebra % 2 === 0} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Continuous;
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/* rc slider https://www.npmjs.com/package/rc-slider */
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import HistogramBrush from "../brushableHistogram";
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
|
@connect((state) => ({
|
||||||
|
schema: (state as any).annoMatrix?.schema,
|
||||||
|
}))
|
||||||
|
class Continuous extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
/* initial value for iterator to simulate index, ranges is an object */
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||||
|
const { schema } = this.props;
|
||||||
|
if (!schema) return null;
|
||||||
|
const obsIndex = schema.annotations.obs.index;
|
||||||
|
const allContinuousNames = schema.annotations.obs.columns
|
||||||
|
.filter((col: any) => col.type === "int32" || col.type === "float32")
|
||||||
|
.filter((col: any) => col.name !== obsIndex)
|
||||||
|
.filter((col: any) => !col.writable) // skip user annotations - they will be treated as categorical
|
||||||
|
.map((col: any) => col.name);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{allContinuousNames.map((key: any, zebra: any) => (
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
|
<HistogramBrush key={key} field={key} isObs zebra={zebra % 2 === 0} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Continuous;
|
||||||
+6
-1
@@ -5,7 +5,7 @@
|
|||||||
******************************************/
|
******************************************/
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
|
||||||
const setupParallelCoordinates = (width, height, margin) => {
|
const setupParallelCoordinates = (width: any, height: any, margin: any) => {
|
||||||
const container = d3.select("#parcoords");
|
const container = d3.select("#parcoords");
|
||||||
|
|
||||||
const svg = container
|
const svg = container
|
||||||
@@ -24,10 +24,15 @@ const setupParallelCoordinates = (width, height, margin) => {
|
|||||||
.style("margin-top", `${margin.top}px`)
|
.style("margin-top", `${margin.top}px`)
|
||||||
.style("margin-left", `${margin.left}px`);
|
.style("margin-left", `${margin.left}px`);
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const ctx = canvas.node().getContext("2d");
|
const ctx = canvas.node().getContext("2d");
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
ctx.globalCompositeOperation = "darken";
|
ctx.globalCompositeOperation = "darken";
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
ctx.globalAlpha = 0.15;
|
ctx.globalAlpha = 0.15;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
ctx.lineWidth = 1.5;
|
ctx.lineWidth = 1.5;
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
ctx.scale(devicePixelRatio, devicePixelRatio);
|
ctx.scale(devicePixelRatio, devicePixelRatio);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -12,14 +12,14 @@ export const innerHeight = height - 2;
|
|||||||
|
|
||||||
export const devicePixelRatio = window.devicePixelRatio || 1;
|
export const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
export const createDimensions = (data) => {
|
export const createDimensions = (data: any) => {
|
||||||
const newArr = [];
|
const newArr: any = [];
|
||||||
each(data, (value, key) => {
|
each(data, (value, key) => {
|
||||||
if (value.range) {
|
if (value.range) {
|
||||||
newArr.push({
|
newArr.push({
|
||||||
key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
|
key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
|
||||||
type: {
|
type: {
|
||||||
within: (d, extent, dim) =>
|
within: (d: any, extent: any, dim: any) =>
|
||||||
extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1],
|
extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1],
|
||||||
},
|
},
|
||||||
scale: d3
|
scale: d3
|
||||||
@@ -32,16 +32,17 @@ export const createDimensions = (data) => {
|
|||||||
return newArr;
|
return newArr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||||
export const yAxis = d3.axisLeft();
|
export const yAxis = d3.axisLeft();
|
||||||
|
|
||||||
export const brushstart = () => {
|
export const brushstart = () => {
|
||||||
d3.event.sourceEvent.stopPropagation();
|
(d3 as any).event.sourceEvent.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unused.
|
// Unused.
|
||||||
// export const d3_functor = v => (typeof v === "function" ? v : () => v);
|
// export const d3_functor = v => (typeof v === "function" ? v : () => v);
|
||||||
export const project = (d, dimensions, xscale) =>
|
export const project = (d: any, dimensions: any, xscale: any) =>
|
||||||
dimensions.map((p, i) => {
|
dimensions.map((p: any, i: any) => {
|
||||||
// check if data element has property and contains a value
|
// check if data element has property and contains a value
|
||||||
if (!(p.key in d) || d[p.key] === null) return null;
|
if (!(p.key in d) || d[p.key] === null) return null;
|
||||||
|
|
||||||
+13
-11
@@ -9,7 +9,7 @@ import {
|
|||||||
} from "../../util/stateManager/colorHelpers";
|
} from "../../util/stateManager/colorHelpers";
|
||||||
|
|
||||||
// create continuous color legend
|
// create continuous color legend
|
||||||
const continuous = (selectorId, colorScale, colorAccessor) => {
|
const continuous = (selectorId: any, colorScale: any, colorAccessor: any) => {
|
||||||
const legendHeight = 200;
|
const legendHeight = 200;
|
||||||
const legendWidth = 80;
|
const legendWidth = 80;
|
||||||
const margin = { top: 10, right: 60, bottom: 10, left: 2 };
|
const margin = { top: 10, right: 60, bottom: 10, left: 2 };
|
||||||
@@ -33,6 +33,7 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
|||||||
we flip the color scale as well [1, 0] instead of [0, 1] */
|
we flip the color scale as well [1, 0] instead of [0, 1] */
|
||||||
.node();
|
.node();
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
const legendScale = d3
|
const legendScale = d3
|
||||||
@@ -44,6 +45,7 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
|||||||
]); /* we flip this to make viridis colors dark if high in the color scale */
|
]); /* 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
|
// image data hackery based on http://bl.ocks.org/mbostock/048d21cf747371b11884f75ad896e5a5
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
const image = ctx.createImageData(1, legendHeight);
|
const image = ctx.createImageData(1, legendHeight);
|
||||||
d3.range(legendHeight).forEach((i) => {
|
d3.range(legendHeight).forEach((i) => {
|
||||||
const c = d3.rgb(colorScale(legendScale.invert(i)));
|
const c = d3.rgb(colorScale(legendScale.invert(i)));
|
||||||
@@ -52,6 +54,7 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
|||||||
image.data[4 * i + 2] = c.b;
|
image.data[4 * i + 2] = c.b;
|
||||||
image.data[4 * i + 3] = 255;
|
image.data[4 * i + 3] = 255;
|
||||||
});
|
});
|
||||||
|
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||||
ctx.putImageData(image, 0, 0);
|
ctx.putImageData(image, 0, 0);
|
||||||
|
|
||||||
// A simpler way to do the above, but possibly slower. keep in mind the legend
|
// A simpler way to do the above, but possibly slower. keep in mind the legend
|
||||||
@@ -105,27 +108,26 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
|||||||
.text(colorAccessor);
|
.text(colorAccessor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: (state as any).annoMatrix,
|
||||||
colors: state.colors,
|
colors: (state as any).colors,
|
||||||
genesets: state.genesets.genesets,
|
genesets: (state as any).genesets.genesets,
|
||||||
}))
|
}))
|
||||||
class ContinuousLegend extends React.Component {
|
class ContinuousLegend extends React.Component {
|
||||||
async componentDidUpdate(prevProps) {
|
async componentDidUpdate(prevProps: any) {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
const { annoMatrix, colors, genesets } = this.props;
|
const { annoMatrix, colors, genesets } = this.props;
|
||||||
if (!colors || !annoMatrix) return;
|
if (!colors || !annoMatrix) return;
|
||||||
|
|
||||||
if (colors !== prevProps?.colors || annoMatrix !== prevProps?.annoMatrix) {
|
if (colors !== prevProps?.colors || annoMatrix !== prevProps?.annoMatrix) {
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorMode, colorAccessor, userColors } = colors;
|
const { colorMode, colorAccessor, userColors } = colors;
|
||||||
|
|
||||||
const colorQuery = createColorQuery(
|
const colorQuery = createColorQuery(
|
||||||
colorMode,
|
colorMode,
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
schema,
|
schema,
|
||||||
genesets
|
genesets
|
||||||
);
|
);
|
||||||
|
|
||||||
const colorDf = colorQuery ? await annoMatrix.fetch(...colorQuery) : null;
|
const colorDf = colorQuery ? await annoMatrix.fetch(...colorQuery) : null;
|
||||||
const colorTable = createColorTable(
|
const colorTable = createColorTable(
|
||||||
colorMode,
|
colorMode,
|
||||||
@@ -134,19 +136,19 @@ class ContinuousLegend extends React.Component {
|
|||||||
schema,
|
schema,
|
||||||
userColors
|
userColors
|
||||||
);
|
);
|
||||||
|
|
||||||
const colorScale = colorTable.scale;
|
const colorScale = colorTable.scale;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'range' does not exist on type '((idx: an... Remove this comment to see the full error message
|
||||||
const range = colorScale?.range;
|
const range = colorScale?.range;
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'domain' does not exist on type '((idx: a... Remove this comment to see the full error message
|
||||||
const [domainMin, domainMax] = colorScale?.domain?.() ?? [0, 0];
|
const [domainMin, domainMax] = colorScale?.domain?.() ?? [0, 0];
|
||||||
|
|
||||||
/* always remove it, if it's not continuous we don't put it back. */
|
/* 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 && range && domainMin < domainMax) {
|
if (colorAccessor && colorScale && range && domainMin < domainMax) {
|
||||||
/* fragile! continuous range is 0 to 1, not [#fa4b2c, ...], make this a flag? */
|
/* fragile! continuous range is 0 to 1, not [#fa4b2c, ...], make this a flag? */
|
||||||
if (range()[0][0] !== "#") {
|
if (range()[0][0] !== "#") {
|
||||||
continuous(
|
continuous(
|
||||||
"#continuous_legend",
|
"#continuous_legend",
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'domain' does not exist on type '((idx: a... Remove this comment to see the full error message
|
||||||
d3.scaleSequential(interpolateCool).domain(colorScale.domain()),
|
d3.scaleSequential(interpolateCool).domain(colorScale.domain()),
|
||||||
colorAccessor
|
colorAccessor
|
||||||
);
|
);
|
||||||
+17
-11
@@ -15,25 +15,30 @@ import * as globals from "../../globals";
|
|||||||
import actions from "../../actions";
|
import actions from "../../actions";
|
||||||
import { getDiscreteCellEmbeddingRowIndex } from "../../util/stateManager/viewStackHelpers";
|
import { getDiscreteCellEmbeddingRowIndex } from "../../util/stateManager/viewStackHelpers";
|
||||||
|
|
||||||
|
type EmbeddingState = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state) => {
|
@connect((state) => {
|
||||||
return {
|
return {
|
||||||
layoutChoice: state.layoutChoice, // TODO: really should clean up naming, s/layout/embedding/g
|
layoutChoice: (state as any).layoutChoice,
|
||||||
schema: state.annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
crossfilter: state.obsCrossfilter,
|
crossfilter: (state as any).obsCrossfilter,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class Embedding extends React.PureComponent {
|
class Embedding extends React.PureComponent<{}, EmbeddingState> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLayoutChoiceChange = (e) => {
|
handleLayoutChoiceChange = (e: any) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
dispatch(actions.layoutChoiceAction(e.currentTarget.value));
|
dispatch(actions.layoutChoiceAction(e.currentTarget.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'layoutChoice' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
const { layoutChoice, schema, crossfilter } = this.props;
|
const { layoutChoice, schema, crossfilter } = this.props;
|
||||||
const { annoMatrix } = crossfilter;
|
const { annoMatrix } = crossfilter;
|
||||||
return (
|
return (
|
||||||
@@ -100,10 +105,11 @@ class Embedding extends React.PureComponent {
|
|||||||
|
|
||||||
export default Embedding;
|
export default Embedding;
|
||||||
|
|
||||||
const loadAllEmbeddingCounts = async ({ annoMatrix, available }) => {
|
const loadAllEmbeddingCounts = async ({ annoMatrix, available }: any) => {
|
||||||
const embeddings = await Promise.all(
|
const embeddings = await Promise.all(
|
||||||
available.map((name) => annoMatrix.base().fetch("emb", name))
|
available.map((name: any) => annoMatrix.base().fetch("emb", name))
|
||||||
);
|
);
|
||||||
|
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'name' implicitly has an 'any' type.
|
||||||
return available.map((name, idx) => ({
|
return available.map((name, idx) => ({
|
||||||
embeddingName: name,
|
embeddingName: name,
|
||||||
embedding: embeddings[idx],
|
embedding: embeddings[idx],
|
||||||
@@ -111,7 +117,7 @@ const loadAllEmbeddingCounts = async ({ annoMatrix, available }) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
|
const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }: any) => {
|
||||||
const { available } = layoutChoice;
|
const { available } = layoutChoice;
|
||||||
const { data, error, isPending } = useAsync({
|
const { data, error, isPending } = useAsync({
|
||||||
promiseFn: loadAllEmbeddingCounts,
|
promiseFn: loadAllEmbeddingCounts,
|
||||||
@@ -127,7 +133,7 @@ const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
|
|||||||
/* still loading, or errored out - just omit counts (TODO: spinner?) */
|
/* still loading, or errored out - just omit counts (TODO: spinner?) */
|
||||||
return (
|
return (
|
||||||
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
||||||
{layoutChoice.available.map((name) => (
|
{layoutChoice.available.map((name: any) => (
|
||||||
<Radio label={`${name}`} value={name} key={name} />
|
<Radio label={`${name}`} value={name} key={name} />
|
||||||
))}
|
))}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
@@ -136,7 +142,7 @@ const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
|
|||||||
if (data) {
|
if (data) {
|
||||||
return (
|
return (
|
||||||
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
||||||
{data.map((summary) => {
|
{data.map((summary: any) => {
|
||||||
const { discreteCellIndex, embeddingName } = summary;
|
const { discreteCellIndex, embeddingName } = summary;
|
||||||
const sizeHint = `${discreteCellIndex.size()} cells`;
|
const sizeHint = `${discreteCellIndex.size()} cells`;
|
||||||
return (
|
return (
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
function Container(props) {
|
function Container(props: any) {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
class Layout extends React.Component {
|
class Layout extends React.Component {
|
||||||
|
viewportRef: any;
|
||||||
/*
|
/*
|
||||||
Layout - this react component contains all the layout style and logic for the application once it has loaded.
|
Layout - this react component contains all the layout style and logic for the application once it has loaded.
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ class Layout extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
|
// @ts-expect-error ts-migrate(2488) FIXME: Type 'ReactNode' must have a '[Symbol.iterator]()'... Remove this comment to see the full error message
|
||||||
const [leftSidebar, renderGraph, rightSidebar] = children;
|
const [leftSidebar, renderGraph, rightSidebar] = children;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
const Logo = (props) => {
|
const Logo = (props: any) => {
|
||||||
const { size } = props;
|
const { size } = props;
|
||||||
return (
|
return (
|
||||||
<svg width={size} height={size} viewBox="0 0 48 48" fill="none">
|
<svg width={size} height={size} viewBox="0 0 48 48" fill="none">
|
||||||
+5
-5
@@ -11,20 +11,20 @@ const ToastTopCenter = Toaster.create({
|
|||||||
/*
|
/*
|
||||||
A "user" error - eg, bad input
|
A "user" error - eg, bad input
|
||||||
*/
|
*/
|
||||||
export const postUserErrorToast = (message) =>
|
export const postUserErrorToast = (message: any) =>
|
||||||
ToastTopCenter.show({ message, intent: Intent.WARNING });
|
ToastTopCenter.show({ message, intent: Intent.WARNING });
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A toast the user must dismiss manually, because they need to act on its information,
|
A toast the user must dismiss manually, because they need to act on its information,
|
||||||
ie., 8 bulk add genes out of 40 were bad. Manually see which ones and fix.
|
ie., 8 bulk add genes out of 40 were bad. Manually see which ones and fix.
|
||||||
*/
|
*/
|
||||||
export const keepAroundErrorToast = (message) =>
|
export const keepAroundErrorToast = (message: any) =>
|
||||||
ToastTopCenter.show({ message, timeout: 0, intent: Intent.WARNING });
|
ToastTopCenter.show({ message, timeout: 0, intent: Intent.WARNING });
|
||||||
|
|
||||||
/*
|
/*
|
||||||
a hard network error
|
a hard network error
|
||||||
*/
|
*/
|
||||||
export const postNetworkErrorToast = (message, key = undefined) =>
|
export const postNetworkErrorToast = (message: any, key = undefined) =>
|
||||||
ToastTopCenter.show(
|
ToastTopCenter.show(
|
||||||
{
|
{
|
||||||
message,
|
message,
|
||||||
@@ -37,14 +37,14 @@ export const postNetworkErrorToast = (message, key = undefined) =>
|
|||||||
/*
|
/*
|
||||||
Async message to user
|
Async message to user
|
||||||
*/
|
*/
|
||||||
export const postAsyncSuccessToast = (message) =>
|
export const postAsyncSuccessToast = (message: any) =>
|
||||||
ToastTopCenter.show({
|
ToastTopCenter.show({
|
||||||
message,
|
message,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
intent: Intent.SUCCESS,
|
intent: Intent.SUCCESS,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const postAsyncFailureToast = (message) =>
|
export const postAsyncFailureToast = (message: any) =>
|
||||||
ToastTopCenter.show({
|
ToastTopCenter.show({
|
||||||
message,
|
message,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
+25
-5
@@ -9,17 +9,23 @@ import actions from "../../actions";
|
|||||||
|
|
||||||
const MINI_HISTOGRAM_WIDTH = 110;
|
const MINI_HISTOGRAM_WIDTH = 110;
|
||||||
|
|
||||||
|
type State = any;
|
||||||
|
|
||||||
|
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||||
@connect((state, ownProps) => {
|
@connect((state, ownProps) => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'gene' does not exist on type '{}'.
|
||||||
const { gene } = ownProps;
|
const { gene } = ownProps;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isColorAccessor: state.colors.colorAccessor === gene,
|
isColorAccessor: (state as any).colors.colorAccessor === gene,
|
||||||
isScatterplotXXaccessor: state.controls.scatterplotXXaccessor === gene,
|
isScatterplotXXaccessor:
|
||||||
isScatterplotYYaccessor: state.controls.scatterplotYYaccessor === gene,
|
(state as any).controls.scatterplotXXaccessor === gene,
|
||||||
|
isScatterplotYYaccessor:
|
||||||
|
(state as any).controls.scatterplotYYaccessor === gene,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class Gene extends React.Component {
|
class Gene extends React.Component<{}, State> {
|
||||||
constructor(props) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
geneIsExpanded: false,
|
geneIsExpanded: false,
|
||||||
@@ -27,6 +33,7 @@ class Gene extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onColorChangeClick = () => {
|
onColorChangeClick = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, gene } = this.props;
|
const { dispatch, gene } = this.props;
|
||||||
dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene));
|
dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene));
|
||||||
};
|
};
|
||||||
@@ -37,6 +44,7 @@ class Gene extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleSetGeneAsScatterplotX = () => {
|
handleSetGeneAsScatterplotX = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, gene } = this.props;
|
const { dispatch, gene } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "set scatterplot x",
|
type: "set scatterplot x",
|
||||||
@@ -45,6 +53,7 @@ class Gene extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleSetGeneAsScatterplotY = () => {
|
handleSetGeneAsScatterplotY = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, gene } = this.props;
|
const { dispatch, gene } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "set scatterplot y",
|
type: "set scatterplot y",
|
||||||
@@ -53,18 +62,26 @@ class Gene extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleDeleteGeneFromSet = () => {
|
handleDeleteGeneFromSet = () => {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||||
const { dispatch, gene, geneset } = this.props;
|
const { dispatch, gene, geneset } = this.props;
|
||||||
dispatch(actions.genesetDeleteGenes(geneset, [gene]));
|
dispatch(actions.genesetDeleteGenes(geneset, [gene]));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'gene' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||||
gene,
|
gene,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'geneDescription' does not exist on type ... Remove this comment to see the full error message
|
||||||
geneDescription,
|
geneDescription,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isColorAccessor' does not exist on type ... Remove this comment to see the full error message
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotXXaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotXXaccessor,
|
isScatterplotXXaccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isScatterplotYYaccessor' does not exist ... Remove this comment to see the full error message
|
||||||
isScatterplotYYaccessor,
|
isScatterplotYYaccessor,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'quickGene' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||||
quickGene,
|
quickGene,
|
||||||
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'removeGene' does not exist on type 'Read... Remove this comment to see the full error message
|
||||||
removeGene,
|
removeGene,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { geneIsExpanded } = this.state;
|
const { geneIsExpanded } = this.state;
|
||||||
@@ -84,6 +101,7 @@ class Gene extends React.Component {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'number | ... Remove this comment to see the full error message
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
data-testclass="gene-expand"
|
data-testclass="gene-expand"
|
||||||
data-testid={`${gene}:gene-expand`}
|
data-testid={`${gene}:gene-expand`}
|
||||||
@@ -124,6 +142,7 @@ class Gene extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
{!geneIsExpanded ? (
|
{!geneIsExpanded ? (
|
||||||
<HistogramBrush
|
<HistogramBrush
|
||||||
|
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||||
isUserDefined
|
isUserDefined
|
||||||
field={gene}
|
field={gene}
|
||||||
mini
|
mini
|
||||||
@@ -188,6 +207,7 @@ class Gene extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||||
{geneIsExpanded && <HistogramBrush isUserDefined field={gene} />}
|
{geneIsExpanded && <HistogramBrush isUserDefined field={gene} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user