mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-21 02:58:13 +08:00
* refactor categorical controls state * lint * fix race condition in tests * fix typo * add missing update on subset * remove obsolete code * update jest and puppeteer major version; update all minors * update when label changes * remove lint from tests; increase timeouts in e2e tests * initial refactoring to new async annomatrix * refine error handling * fix bad merge * add continuous legend * lint * fix memoization in color table creators * partial implementation of user defined annotations * add new annotations action creator file * first pass at user annotations * additional user annotation bug fixes * user annotation auto-save * unit test cleanup * lint * refactor into multiple files * cleanup * add column GC * fix several bugs in user annotations * remove debug code * no anonymous functions * undo redo cleanup * file cleanup * scatterplot * performance * cleanup * remove old code * render in parallel with load * fix race condition * simply graph rendering * render throttle DRY * fix category label order * fix typo in e2e test setup * re-fix the e2e test setup * be more tolerant of races * anno matrix unit tests * temp disable reembedding * pilot port continuous histo to react-async * name change * lint * fix repaint bug * typo fix * update snap to match new ids * world/universe name cleanup * move annoMatrix to src dir * use private underscore naming convention * fix corner case in all selected * name cleanup * add layout control * init edge case * lint * port scatterplot * fix label indexing bug and improve tests * port category to react-async * fix user annotation labelling while subset * select all of prev layout on layout switch * fix race with crossfilter update * prettier lint * fix misleading comment * fix url composition in loader * first pass at crossfilter tests * lint * lint * fix typo * improved error handling for network errors * fix memoization bug * add memo * refactor for performnce * add missing single-value handling in select exact parser * small bugs discovered by tests * lint * additional crossfilter unit tests * remove extraneous comment * add support for automatic category determination * lint * fix render bug in category * take advantage of schema categories guarantee * lint * do not clear history when resetting * enhanced annomatrix gc * lint * finish renaming to follow conventions; fix clone race bug * lint * add priority based loading to improve initial data load UX * crossfilter cache perf * perf tuning * remove timers * documentation * PR review changes * PR review changes * more PR review edits * improve clarity of comment * more PR review fixes * port centroidLabels to use react-async * remove dead code * pr review updates * oops, remove logging
130 lines
3.2 KiB
JavaScript
130 lines
3.2 KiB
JavaScript
import _ from "lodash";
|
|
/* XXX: cough, cough, ... */
|
|
import { postNetworkErrorToast } from "../components/framework/toasters";
|
|
|
|
/*
|
|
dispatch an action error to the user. Currently we use
|
|
async toasts.
|
|
*/
|
|
let networkErrorToastKey = null;
|
|
export const dispatchNetworkErrorMessageToUser = (message) => {
|
|
if (!networkErrorToastKey) {
|
|
networkErrorToastKey = postNetworkErrorToast(message);
|
|
} else {
|
|
postNetworkErrorToast(message, networkErrorToastKey);
|
|
}
|
|
};
|
|
|
|
/*
|
|
Catch unexpected errors and make sure we don't lose them!
|
|
*/
|
|
export function catchErrorsWrap(fn, dispatchToUser = false) {
|
|
return (dispatch, getState) => {
|
|
fn(dispatch, getState).catch((error) => {
|
|
console.error(error);
|
|
if (dispatchToUser) {
|
|
dispatchNetworkErrorMessageToUser(error.message);
|
|
}
|
|
dispatch({ type: "UNEXPECTED ERROR", error });
|
|
});
|
|
};
|
|
}
|
|
|
|
/*
|
|
Wrapper to perform async fetch with some modest error handling
|
|
and decoding.
|
|
*/
|
|
const doFetch = async (url, acceptType) => {
|
|
try {
|
|
const res = await fetch(url, {
|
|
method: "get",
|
|
headers: new Headers({
|
|
Accept: acceptType,
|
|
}),
|
|
credentials: "include",
|
|
});
|
|
if (res.ok && res.headers.get("Content-Type").includes(acceptType)) {
|
|
return res;
|
|
}
|
|
// else an error
|
|
const msg = `Unexpected HTTP response ${res.status}, ${res.statusText}`;
|
|
dispatchNetworkErrorMessageToUser(msg);
|
|
throw new Error(msg);
|
|
} catch (e) {
|
|
// network error
|
|
const msg = "Unexpected HTTP error";
|
|
dispatchNetworkErrorMessageToUser(msg);
|
|
throw e;
|
|
}
|
|
};
|
|
|
|
/*
|
|
Wrapper to perform an async fetch and JSON decode response.
|
|
*/
|
|
export const doJsonRequest = async (url) => {
|
|
const res = await doFetch(url, "application/json");
|
|
return res.json();
|
|
};
|
|
|
|
/*
|
|
Wrapper to perform an async fetch for binary data.
|
|
*/
|
|
export const doBinaryRequest = async (url) => {
|
|
const res = await doFetch(url, "application/octet-stream");
|
|
return res.arrayBuffer();
|
|
};
|
|
|
|
/*
|
|
This function "packs" filter index lists into the more efficient
|
|
"range" form specified in the REST 0.2 spec.
|
|
|
|
Specifically, it turns an array of indices [0, 1, 2, 10, 11, 14, ...]
|
|
into a form that encodes runs of consecutive numbers as [min, max].
|
|
Array may not be sorted, but will only contain uniq values.
|
|
|
|
Parameters:
|
|
indices - input array of numbers (index)
|
|
minRangeLength - hint, min range length before it is encoded into range format.
|
|
sorted - boolean hint indicating array is presorted, ascending order
|
|
|
|
So [1, 2, 3, 4, 10, 11, 14] -> [ [1, 4], [10, 11], 14]
|
|
*/
|
|
export const rangeEncodeIndices = (
|
|
indices,
|
|
minRangeLength = 3,
|
|
sorted = false
|
|
) => {
|
|
if (indices.length === 0) {
|
|
return indices;
|
|
}
|
|
|
|
if (!sorted) {
|
|
indices = _.sortBy(indices);
|
|
}
|
|
|
|
const result = new Array(indices.length);
|
|
let resultTail = 0;
|
|
|
|
let i = 0;
|
|
while (i < indices.length) {
|
|
const begin = indices[i];
|
|
let current;
|
|
do {
|
|
current = indices[i];
|
|
i += 1;
|
|
} while (i < indices.length && indices[i] === current + 1);
|
|
|
|
if (current - begin + 1 >= minRangeLength) {
|
|
result[resultTail] = [begin, current];
|
|
resultTail += 1;
|
|
} else {
|
|
for (let j = begin; j <= current; j += 1, resultTail += 1) {
|
|
result[resultTail] = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
result.length = resultTail;
|
|
return result;
|
|
};
|