Files
cellxgene/client/src/util/actionHelpers.js
T
Bruce Martin 99a795a688 Updating front-end dependencies (#2167)
* update to webpack 5

* update babel

* update eslint

* update cheerio

* update npm min to v7

* revert engine change

* generate package lock with npm v6 (lockfileVersion 1)

* add region to test setup

* update blueprint popover2

* tabindex changes due to blueprint popover2 revision

* update snapshots

* update lodash and pako

* fix typo

* fix lodash refactoring

* more lodash refactoring

* update babel and blueprintjs

* update jest support packages

* update puppeteer

* update regl

* update react-icons and react-helmet

* update react and react-dom
2021-04-21 07:23:31 -07:00

141 lines
3.5 KiB
JavaScript

import sortBy from "lodash.sortby";
/* 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. Arguments are identical to standard fetch.
*/
export const doFetch = async (url, init = {}) => {
try {
// add defaults to the fetch init param.
init = {
method: "get",
credentials: "include",
...init,
};
const acceptType = init.headers?.get("Accept");
const res = await fetch(url, init);
if (
res.ok &&
(!acceptType || 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, init = {}) => {
const res = await doFetch(url, {
...init,
headers: new Headers({ Accept: "application/json" }),
});
return res.json();
};
/*
Wrapper to perform an async fetch for binary data.
*/
export const doBinaryRequest = async (url, init = {}) => {
const res = await doFetch(url, {
...init,
headers: new Headers({ Accept: "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;
};