thebe-react
Version:
React providers and components for thebe-core
269 lines • 12.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useNotebookfromSourceLegacy = exports.useNotebookFromSource = exports.useNotebook = exports.useNotebookBase = exports.findErrors = void 0;
const react_1 = require("react");
const ThebeServerProvider_1 = require("../ThebeServerProvider");
const ThebeLoaderProvider_1 = require("../ThebeLoaderProvider");
const ThebeSessionProvider_1 = require("../ThebeSessionProvider");
const ThebeRenderMimeRegistryProvider_1 = require("../ThebeRenderMimeRegistryProvider");
function findErrors(execReturns) {
return execReturns.reduce((acc, retval, index) => {
if (retval === null || retval === void 0 ? void 0 : retval.error) {
if (acc == null)
return [Object.assign(Object.assign({}, retval), { index })];
else
return [...acc, Object.assign(Object.assign({}, retval), { index })];
}
return acc;
}, null);
}
exports.findErrors = findErrors;
function useNotebookBase() {
const { session, ready: sessionReady } = (0, ThebeSessionProvider_1.useThebeSession)();
const [notebook, setNotebook] = (0, react_1.useState)();
// TODO move the refs to caller hooks as it does so little to maintain them in here.
const [refs, setRefs] = (0, react_1.useState)([]);
const [sessionAttached, setSessionAttached] = (0, react_1.useState)(false);
const [executing, setExecuting] = (0, react_1.useState)(false);
const [executed, setExecuted] = (0, react_1.useState)(false);
const [errors, setErrors] = (0, react_1.useState)(null);
/**
* When the notebook and session is avaiable, attach to session
*/
(0, react_1.useEffect)(() => {
if (!notebook || !session || !sessionReady)
return;
console.debug(`thebe-react: attaching notebook to session`, { notebook, session });
notebook.attachSession(session);
setSessionAttached(true);
}, [notebook, session, sessionReady]);
const executeAll = (options) => {
var _a, _b;
if (!notebook)
throw new Error('executeAll called before notebook available');
if (!session)
throw new Error('executeAll called before session available');
(_a = options === null || options === void 0 ? void 0 : options.before) === null || _a === void 0 ? void 0 : _a.call(options);
setExecuting(true);
return notebook
.executeAll((_b = options === null || options === void 0 ? void 0 : options.stopOnError) !== null && _b !== void 0 ? _b : true, options === null || options === void 0 ? void 0 : options.preprocessor)
.then((execReturns) => {
var _a;
(_a = options === null || options === void 0 ? void 0 : options.after) === null || _a === void 0 ? void 0 : _a.call(options);
const errs = findErrors(execReturns);
if (errs != null)
setErrors(errs);
setExecuted(true);
setExecuting(false);
return execReturns;
});
};
const executeSome = (predicate, options) => {
var _a, _b;
if (!notebook)
throw new Error('executeSome called before notebook available');
if (!session)
throw new Error('executeAll called before session available');
(_a = options === null || options === void 0 ? void 0 : options.before) === null || _a === void 0 ? void 0 : _a.call(options);
setExecuting(true);
const filteredCells = notebook.cells.filter(predicate).map((c) => c.id);
return notebook
.executeCells(filteredCells, (_b = options === null || options === void 0 ? void 0 : options.stopOnError) !== null && _b !== void 0 ? _b : true, options === null || options === void 0 ? void 0 : options.preprocessor)
.then((execReturns) => {
var _a;
(_a = options === null || options === void 0 ? void 0 : options.after) === null || _a === void 0 ? void 0 : _a.call(options);
const errs = findErrors(execReturns);
if (errs != null)
setErrors(errs);
setExecuted(true);
setExecuting(false);
return execReturns;
});
};
const clear = () => {
if (!notebook)
throw new Error('clear called before notebook available');
notebook.clear();
setExecuted(false);
};
return {
ready: !!notebook && sessionAttached,
attached: sessionAttached,
executing,
executed,
errors,
notebook,
setNotebook,
refs,
setRefs,
executeAll,
executeSome,
clear,
session,
};
}
exports.useNotebookBase = useNotebookBase;
/**
* @param name - provided to the fetcher function
* @param fetchNotebook - an async function, that given a name, can return a JSON representation of an ipynb file (INotebookContent)
* @param opts - options.refsForWidgetsOnly=false allows refs to be generated for all notebook cells, rather than onlythose with widget tags
* @returns
*/
function useNotebook(name, fetchNotebook, opts = { refsForWidgetsOnly: true }) {
var _a, _b;
const { core } = (0, ThebeLoaderProvider_1.useThebeLoader)();
const { config } = (0, ThebeServerProvider_1.useThebeConfig)();
const rendermime = (0, ThebeRenderMimeRegistryProvider_1.useRenderMimeRegistry)();
const [loading, setLoading] = (0, react_1.useState)(false);
if (!rendermime)
throw new Error('ThebeSessionProvider requires a RenderMimeRegistryProvider');
const { ready, attached, executing, executed, errors, notebook, setNotebook, refs, setRefs, executeAll, executeSome, clear, session, } = useNotebookBase();
/**
* - set loading flag
* - load the notebook
* - setup callback refs, to auto-attach to dom
* - set notebook, which triggers
* - clear loading flag
*/
(0, react_1.useEffect)(() => {
if (!core || !config)
return;
setLoading(true);
fetchNotebook(name)
.then((ipynb) => {
return core === null || core === void 0 ? void 0 : core.ThebeNotebook.fromIpynb(ipynb, config, rendermime);
})
.then((nb) => {
var _a, _b;
const cells = (opts === null || opts === void 0 ? void 0 : opts.refsForWidgetsOnly) ? (_a = nb === null || nb === void 0 ? void 0 : nb.widgets) !== null && _a !== void 0 ? _a : [] : (_b = nb === null || nb === void 0 ? void 0 : nb.cells) !== null && _b !== void 0 ? _b : [];
// set up an array of callback refs to update the DOM elements
setRefs(Array(cells.length)
.fill(null)
.map((_, idx) => (node) => {
console.debug(`new ref[${idx}] - attaching to dom...`, node);
if (node != null)
cells[idx].attachToDOM(node);
}));
setNotebook(nb);
setLoading(false);
});
}, [core, config]);
return {
ready,
loading,
attached,
executing,
executed,
errors,
notebook,
cellRefs: refs,
cellIds: (opts.refsForWidgetsOnly ? (_a = notebook === null || notebook === void 0 ? void 0 : notebook.widgets) !== null && _a !== void 0 ? _a : [] : (_b = notebook === null || notebook === void 0 ? void 0 : notebook.cells) !== null && _b !== void 0 ? _b : []).map((c) => c.id),
executeAll,
executeSome,
clear,
session,
};
}
exports.useNotebook = useNotebook;
/**
* @param sourceCode - just an array of valid code blocks as single line strings
* @param opts - options.refsForWidgetsOnly=false allows refs to be generated for all notebook cells, rather than onlythose with widget tags
* @returns
*/
function useNotebookFromSource(sourceCode, opts = { refsForWidgetsOnly: true }) {
var _a, _b;
const { core } = (0, ThebeLoaderProvider_1.useThebeLoader)();
const { config } = (0, ThebeServerProvider_1.useThebeConfig)();
const rendermime = (0, ThebeRenderMimeRegistryProvider_1.useRenderMimeRegistry)();
const [loading, setLoading] = (0, react_1.useState)(false);
if (!rendermime)
throw new Error('ThebeSessionProvider requires a RenderMimeRegistryProvider');
const { ready, attached, executing, executed, errors, notebook, setNotebook, refs, setRefs, executeAll, executeSome, clear, session, } = useNotebookBase();
(0, react_1.useEffect)(() => {
var _a, _b;
if (!core || !config || loading || notebook)
return;
setLoading(true);
const nb = core.ThebeNotebook.fromCodeBlocks(sourceCode.map((source) => ({ id: core === null || core === void 0 ? void 0 : core.shortId(), source })), config, rendermime);
const cells = (opts === null || opts === void 0 ? void 0 : opts.refsForWidgetsOnly) ? (_a = nb === null || nb === void 0 ? void 0 : nb.widgets) !== null && _a !== void 0 ? _a : [] : (_b = nb === null || nb === void 0 ? void 0 : nb.cells) !== null && _b !== void 0 ? _b : [];
setRefs(Array(cells.length)
.fill(null)
.map((_, idx) => (node) => {
console.debug(`new ref[${idx}] - attaching to dom...`, node);
if (node != null)
cells[idx].attachToDOM(node);
}));
setNotebook(nb);
setLoading(false);
}, [core, notebook, loading]);
return {
ready,
loading,
attached,
executing,
executed,
errors,
notebook,
cellRefs: refs,
cellIds: (opts.refsForWidgetsOnly ? (_a = notebook === null || notebook === void 0 ? void 0 : notebook.widgets) !== null && _a !== void 0 ? _a : [] : (_b = notebook === null || notebook === void 0 ? void 0 : notebook.cells) !== null && _b !== void 0 ? _b : []).map((c) => c.id),
executeAll,
executeSome,
clear,
session,
};
}
exports.useNotebookFromSource = useNotebookFromSource;
/**
* DEPRECATED - migrate to useNotebookFromSource
*/
function useNotebookfromSourceLegacy(sourceCode) {
const { core } = (0, ThebeLoaderProvider_1.useThebeLoader)();
const { config } = (0, ThebeServerProvider_1.useThebeConfig)();
const rendermime = (0, ThebeRenderMimeRegistryProvider_1.useRenderMimeRegistry)();
if (!rendermime)
throw new Error('ThebeSessionProvider requires a RenderMimeRegistryProvider');
const [busy, setBusy] = (0, react_1.useState)(false);
const [notebook, setNotebook] = (0, react_1.useState)();
const [_, setReRender] = (0, react_1.useState)({});
const [cellRefs] = (0, react_1.useState)(Array(sourceCode.length)
.fill(undefined)
.map(() => (0, react_1.createRef)()));
(0, react_1.useEffect)(() => {
if (!core || !config || notebook)
return;
setNotebook(core.ThebeNotebook.fromCodeBlocks(sourceCode.map((source) => ({ id: core === null || core === void 0 ? void 0 : core.shortId(), source })), config, rendermime));
}, [core, notebook]);
const execute = () => {
if (!notebook)
throw new Error('execute called before notebook available');
setBusy(true);
notebook.executeAll().then(() => {
setBusy(false);
});
};
const attach = (session) => {
if (session.kernel == null)
return;
if (!notebook) {
console.warn('attach called before notebook available');
return;
}
notebook === null || notebook === void 0 ? void 0 : notebook.detachSession();
notebook === null || notebook === void 0 ? void 0 : notebook.attachSession(session);
notebook === null || notebook === void 0 ? void 0 : notebook.cells.forEach((cell, idx) => {
var _a;
if (cellRefs[idx].current)
cell.attachToDOM((_a = cellRefs[idx].current) !== null && _a !== void 0 ? _a : undefined);
});
};
return {
notebook,
busy,
execute,
attach,
cellRefs,
rerender: () => setReRender({}),
};
}
exports.useNotebookfromSourceLegacy = useNotebookfromSourceLegacy;
//# sourceMappingURL=notebook.js.map