@myst-theme/jupyter 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/cjs/components.d.ts +10 -0
- package/dist/cjs/components.d.ts.map +1 -0
- package/dist/cjs/components.js +41 -0
- package/dist/cjs/error.d.ts +6 -0
- package/dist/cjs/error.d.ts.map +1 -0
- package/dist/cjs/error.js +15 -0
- package/dist/cjs/hooks.d.ts +67 -0
- package/dist/cjs/hooks.d.ts.map +1 -0
- package/dist/cjs/hooks.js +85 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/jupyter.d.ts +7 -0
- package/dist/cjs/jupyter.d.ts.map +1 -0
- package/dist/cjs/jupyter.js +75 -0
- package/dist/cjs/output.d.ts +7 -0
- package/dist/cjs/output.d.ts.map +1 -0
- package/dist/cjs/output.js +66 -0
- package/dist/cjs/outputBlock.d.ts +10 -0
- package/dist/cjs/outputBlock.d.ts.map +1 -0
- package/dist/cjs/outputBlock.js +13 -0
- package/dist/cjs/safe.d.ts +7 -0
- package/dist/cjs/safe.d.ts.map +1 -0
- package/dist/cjs/safe.js +77 -0
- package/dist/cjs/selectors.d.ts +10 -0
- package/dist/cjs/selectors.d.ts.map +1 -0
- package/dist/cjs/selectors.js +10 -0
- package/dist/cjs/stream.d.ts +6 -0
- package/dist/cjs/stream.d.ts.map +1 -0
- package/dist/cjs/stream.js +13 -0
- package/dist/esm/components.d.ts +10 -0
- package/dist/esm/components.d.ts.map +1 -0
- package/dist/esm/components.js +36 -0
- package/dist/esm/error.d.ts +6 -0
- package/dist/esm/error.d.ts.map +1 -0
- package/dist/esm/error.js +9 -0
- package/dist/esm/hooks.d.ts +67 -0
- package/dist/esm/hooks.d.ts.map +1 -0
- package/dist/esm/hooks.js +76 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/jupyter.d.ts +7 -0
- package/dist/esm/jupyter.d.ts.map +1 -0
- package/dist/esm/jupyter.js +48 -0
- package/dist/esm/output.d.ts +7 -0
- package/dist/esm/output.d.ts.map +1 -0
- package/dist/esm/output.js +57 -0
- package/dist/esm/outputBlock.d.ts +10 -0
- package/dist/esm/outputBlock.d.ts.map +1 -0
- package/dist/esm/outputBlock.js +6 -0
- package/dist/esm/safe.d.ts +7 -0
- package/dist/esm/safe.d.ts.map +1 -0
- package/dist/esm/safe.js +70 -0
- package/dist/esm/selectors.d.ts +10 -0
- package/dist/esm/selectors.d.ts.map +1 -0
- package/dist/esm/selectors.js +4 -0
- package/dist/esm/stream.d.ts +6 -0
- package/dist/esm/stream.d.ts.map +1 -0
- package/dist/esm/stream.js +7 -0
- package/dist/types/components.d.ts +10 -0
- package/dist/types/components.d.ts.map +1 -0
- package/dist/types/error.d.ts +6 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/hooks.d.ts +67 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/jupyter.d.ts +7 -0
- package/dist/types/jupyter.d.ts.map +1 -0
- package/dist/types/output.d.ts +7 -0
- package/dist/types/output.d.ts.map +1 -0
- package/dist/types/outputBlock.d.ts +10 -0
- package/dist/types/outputBlock.d.ts.map +1 -0
- package/dist/types/safe.d.ts +7 -0
- package/dist/types/safe.d.ts.map +1 -0
- package/dist/types/selectors.d.ts +10 -0
- package/dist/types/selectors.d.ts.map +1 -0
- package/dist/types/stream.d.ts +6 -0
- package/dist/types/stream.d.ts.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { useEffect, useRef } from 'react';
|
|
14
|
+
import { useLongContent } from './hooks';
|
|
15
|
+
export const MaybeLongContent = ({ content, path, render, }) => {
|
|
16
|
+
const { error, data } = useLongContent(content, path);
|
|
17
|
+
if (error) {
|
|
18
|
+
return _jsxs("div", Object.assign({ className: "text-red-500" }, { children: ["Error loading content: ", error.message] }));
|
|
19
|
+
}
|
|
20
|
+
if (!data) {
|
|
21
|
+
return _jsx("div", { children: "Fetching long content...." });
|
|
22
|
+
}
|
|
23
|
+
return _jsx("div", { children: render(data.content) });
|
|
24
|
+
};
|
|
25
|
+
export const DangerousHTML = (_a) => {
|
|
26
|
+
var { content } = _a, rest = __rest(_a, ["content"]);
|
|
27
|
+
const ref = useRef(null);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!content || !ref.current)
|
|
30
|
+
return;
|
|
31
|
+
const el = document.createRange().createContextualFragment(content);
|
|
32
|
+
ref.current.innerHTML = '';
|
|
33
|
+
ref.current.appendChild(el);
|
|
34
|
+
}, [content, ref]);
|
|
35
|
+
return _jsx("div", Object.assign({}, rest, { ref: ref }));
|
|
36
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/error.tsx"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,eAcxE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Ansi from 'ansi-to-react';
|
|
3
|
+
import { ensureString } from '@curvenote/blocks';
|
|
4
|
+
import { MaybeLongContent } from './components';
|
|
5
|
+
export default function Error({ output }) {
|
|
6
|
+
return (_jsx(MaybeLongContent, { content: ensureString(output.traceback), path: output.path, render: (content) => {
|
|
7
|
+
return (_jsx("pre", Object.assign({ className: "text-sm font-thin font-system jupyter-error" }, { children: _jsx(Ansi, { children: content !== null && content !== void 0 ? content : '' }) })));
|
|
8
|
+
} }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { MinifiedOutput } from '@curvenote/nbtx/dist/minify/types';
|
|
2
|
+
/**
|
|
3
|
+
* Truncation vs Summarization
|
|
4
|
+
*
|
|
5
|
+
* In Curvespace, we're decided to change our data structure for outputs to align it as
|
|
6
|
+
* closely as possible with Jupyters nbformat.IOutput[] type, but in a way that still allows
|
|
7
|
+
* us to truncate output content and push that to storage.
|
|
8
|
+
*
|
|
9
|
+
* This will be used only in the CLI and Curvespace initially but should be ported back to
|
|
10
|
+
* the rest of the code base. This will mean
|
|
11
|
+
*
|
|
12
|
+
* - changing the DB schema
|
|
13
|
+
* - migration
|
|
14
|
+
* - changing API response
|
|
15
|
+
* - changing the frontend
|
|
16
|
+
* - changing the extension
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
interface LongContent {
|
|
20
|
+
content_type?: string;
|
|
21
|
+
content: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function useLongContent(content?: string, url?: string): {
|
|
24
|
+
data?: LongContent;
|
|
25
|
+
error?: Error;
|
|
26
|
+
};
|
|
27
|
+
export declare function useFetchAnyTruncatedContent(outputs: MinifiedOutput[]): {
|
|
28
|
+
data: ({
|
|
29
|
+
data: {};
|
|
30
|
+
path?: string | undefined;
|
|
31
|
+
traceback: string & string[];
|
|
32
|
+
output_type: "error";
|
|
33
|
+
ename: string;
|
|
34
|
+
evalue: string;
|
|
35
|
+
} | {
|
|
36
|
+
data: {};
|
|
37
|
+
path?: string | undefined;
|
|
38
|
+
output_type: "stream";
|
|
39
|
+
name: import("@jupyterlab/nbformat").StreamType;
|
|
40
|
+
text: import("@jupyterlab/nbformat").MultilineString;
|
|
41
|
+
} | {
|
|
42
|
+
data: {};
|
|
43
|
+
output_type: import("@curvenote/nbtx/dist/minify/types").MimeOutputType;
|
|
44
|
+
execution_count?: import("@jupyterlab/nbformat").ExecutionCount | undefined;
|
|
45
|
+
metadata: import("@lumino/coreutils").PartialJSONObject;
|
|
46
|
+
} | {
|
|
47
|
+
[x: string]: import("@lumino/coreutils").PartialJSONValue | undefined;
|
|
48
|
+
path?: string | undefined;
|
|
49
|
+
traceback: string & string[];
|
|
50
|
+
output_type: "error";
|
|
51
|
+
ename: string;
|
|
52
|
+
evalue: string;
|
|
53
|
+
} | {
|
|
54
|
+
[x: string]: import("@lumino/coreutils").PartialJSONValue | undefined;
|
|
55
|
+
path?: string | undefined;
|
|
56
|
+
output_type: "stream";
|
|
57
|
+
name: import("@jupyterlab/nbformat").StreamType;
|
|
58
|
+
text: import("@jupyterlab/nbformat").MultilineString;
|
|
59
|
+
})[] | undefined;
|
|
60
|
+
error: any;
|
|
61
|
+
};
|
|
62
|
+
export default function useWindowSize(): {
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
};
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,cAAc,EAEf,MAAM,mCAAmC,CAAC;AAI3C;;;;;;;;;;;;;;;;GAgBG;AAEH,UAAU,WAAW;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,cAAc,CAC5B,OAAO,CAAC,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,GACX;IAAE,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAQvC;AAuBD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BpE;AAUD,MAAM,CAAC,OAAO,UAAU,aAAa;;;EAapC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import useSWRImmutable from 'swr/immutable';
|
|
2
|
+
import { walkPaths } from '@curvenote/nbtx/dist/minify/utils';
|
|
3
|
+
import { useState, useLayoutEffect } from 'react';
|
|
4
|
+
const fetcher = (...args) => fetch(...args).then((res) => {
|
|
5
|
+
if (res.status === 200)
|
|
6
|
+
return res.json();
|
|
7
|
+
throw new Error(`Content returned with status ${res.status}.`);
|
|
8
|
+
});
|
|
9
|
+
export function useLongContent(content, url) {
|
|
10
|
+
if (typeof document === 'undefined') {
|
|
11
|
+
// This is ONLY called on the server
|
|
12
|
+
return url ? {} : { data: { content: content !== null && content !== void 0 ? content : '' } };
|
|
13
|
+
}
|
|
14
|
+
const { data, error } = useSWRImmutable(url || null, fetcher);
|
|
15
|
+
if (!url)
|
|
16
|
+
return { data: { content: content !== null && content !== void 0 ? content : '' } };
|
|
17
|
+
return { data, error };
|
|
18
|
+
}
|
|
19
|
+
const arrayFetcher = (...urls) => {
|
|
20
|
+
return Promise.all(urls.map((url) => fetcher(url)));
|
|
21
|
+
};
|
|
22
|
+
function shallowCloneOutputs(outputs) {
|
|
23
|
+
return outputs.map((output) => {
|
|
24
|
+
if ('data' in output && output.data) {
|
|
25
|
+
const data = output.data;
|
|
26
|
+
return Object.assign(Object.assign({}, output), { data: Object.entries(data).reduce((acc, [mimetype, payload]) => {
|
|
27
|
+
return Object.assign(Object.assign({}, acc), { [mimetype]: Object.assign({}, payload) });
|
|
28
|
+
}, {}) });
|
|
29
|
+
}
|
|
30
|
+
return Object.assign({}, output);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function useFetchAnyTruncatedContent(outputs) {
|
|
34
|
+
const itemsWithPaths = [];
|
|
35
|
+
const updated = shallowCloneOutputs(outputs);
|
|
36
|
+
walkPaths(updated, (path, obj) => {
|
|
37
|
+
// images have paths, but we don't need to fetch them
|
|
38
|
+
if ('content_type' in obj && obj.content_type.startsWith('image/'))
|
|
39
|
+
return;
|
|
40
|
+
obj.path = path;
|
|
41
|
+
itemsWithPaths.push(obj);
|
|
42
|
+
});
|
|
43
|
+
const { data, error } = useSWRImmutable(itemsWithPaths.map(({ path }) => path), arrayFetcher);
|
|
44
|
+
data === null || data === void 0 ? void 0 : data.forEach(({ content }, idx) => {
|
|
45
|
+
const obj = itemsWithPaths[idx];
|
|
46
|
+
if ('text' in obj)
|
|
47
|
+
obj.text = content; // stream
|
|
48
|
+
if ('traceback' in obj)
|
|
49
|
+
obj.traceback = content; // error
|
|
50
|
+
if ('content' in obj)
|
|
51
|
+
obj.content = content; // mimeoutput
|
|
52
|
+
obj.path = undefined;
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
data: itemsWithPaths.length === 0 || data ? updated : undefined,
|
|
56
|
+
error,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function getWindowSize() {
|
|
60
|
+
const { innerWidth: width, innerHeight: height } = window;
|
|
61
|
+
return {
|
|
62
|
+
width,
|
|
63
|
+
height,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export default function useWindowSize() {
|
|
67
|
+
const [windowSize, setWindowSize] = useState(getWindowSize());
|
|
68
|
+
useLayoutEffect(() => {
|
|
69
|
+
function handleResize() {
|
|
70
|
+
setWindowSize(getWindowSize());
|
|
71
|
+
}
|
|
72
|
+
window.addEventListener('resize', handleResize);
|
|
73
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
74
|
+
}, []);
|
|
75
|
+
return windowSize;
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,QAAA,MAAM,gBAAgB;;CAErB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jupyter.d.ts","sourceRoot":"","sources":["../../src/jupyter.tsx"],"names":[],"mappings":";AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQtD,eAAO,MAAM,oBAAoB;QAI3B,MAAM;aACD,cAAc,EAAE;iBAmE1B,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import useWindowSize, { useFetchAnyTruncatedContent } from './hooks';
|
|
4
|
+
import { nanoid } from 'nanoid';
|
|
5
|
+
import { useSelector } from 'react-redux';
|
|
6
|
+
import { host, actions } from '@curvenote/connect';
|
|
7
|
+
import { convertToIOutputs, fetchAndEncodeOutputImages } from '@curvenote/nbtx';
|
|
8
|
+
import { ChevronDoubleDownIcon } from '@heroicons/react/24/outline';
|
|
9
|
+
import { selectIFrameHeight, selectIFrameReady } from './selectors';
|
|
10
|
+
const PERCENT_OF_WINDOW = 0.9;
|
|
11
|
+
export const NativeJupyterOutputs = ({ id, outputs, }) => {
|
|
12
|
+
const windowSize = useWindowSize();
|
|
13
|
+
const { data, error } = useFetchAnyTruncatedContent(outputs);
|
|
14
|
+
const [loading, setLoading] = useState(true);
|
|
15
|
+
const [frameHeight, setFrameHeight] = useState(0);
|
|
16
|
+
const [clamped, setClamped] = useState(false);
|
|
17
|
+
const uid = useMemo(nanoid, []);
|
|
18
|
+
const height = useSelector((state) => selectIFrameHeight(state, uid));
|
|
19
|
+
const rendererReady = useSelector((state) => selectIFrameReady(state, uid));
|
|
20
|
+
const iframeRef = useRef(null);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (iframeRef.current == null || !rendererReady || !data)
|
|
23
|
+
return;
|
|
24
|
+
fetchAndEncodeOutputImages(convertToIOutputs(data)).then((out) => {
|
|
25
|
+
host.commsDispatch(iframeRef.current, actions.connectHostSendContent(uid, out));
|
|
26
|
+
});
|
|
27
|
+
}, [id, iframeRef.current, rendererReady]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (height == null)
|
|
30
|
+
return;
|
|
31
|
+
if (height > PERCENT_OF_WINDOW * windowSize.height) {
|
|
32
|
+
setFrameHeight(PERCENT_OF_WINDOW * windowSize.height);
|
|
33
|
+
setClamped(true);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
setFrameHeight(height + 25);
|
|
37
|
+
setClamped(false);
|
|
38
|
+
}
|
|
39
|
+
setLoading(false);
|
|
40
|
+
}, [height]);
|
|
41
|
+
if (error) {
|
|
42
|
+
return _jsxs("div", Object.assign({ className: "text-red-500" }, { children: ["Error rendering output: ", error.message] }));
|
|
43
|
+
}
|
|
44
|
+
return (_jsxs("div", { children: [loading && _jsx("div", Object.assign({ className: "p-2.5" }, { children: "Loading..." })), _jsx("iframe", { ref: iframeRef, id: uid, name: uid, title: uid, src: "https://next.curvenote.run", width: '100%', height: frameHeight, sandbox: "allow-scripts" }), clamped && (_jsx("div", Object.assign({ className: "cursor-pointer p-1 pb-2 hover:bg-gray-50 dark:hover:bg-gray-700 text-center text-gray-500 hover:text-gray-600 dark:text-gray-200 dark:hover:text-gray-50", title: "Expand", onClick: () => {
|
|
45
|
+
setFrameHeight(height !== null && height !== void 0 ? height : 0);
|
|
46
|
+
setClamped(false);
|
|
47
|
+
} }, { children: _jsx(ChevronDoubleDownIcon, { className: "w-5 h-5 inline" }) })))] }));
|
|
48
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { GenericNode } from 'mystjs';
|
|
3
|
+
import type { MinifiedOutput } from '@curvenote/nbtx/dist/minify/types';
|
|
4
|
+
export declare function allOutputsAreSafe(outputs: MinifiedOutput[], directOutputTypes: Set<string>, directMimeTypes: Set<string>): boolean;
|
|
5
|
+
export declare function anyErrors(outputs: MinifiedOutput[]): boolean;
|
|
6
|
+
export declare function Output(node: GenericNode): JSX.Element;
|
|
7
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/output.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAgB5F,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,cAAc,EAAE,EACzB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAY7B;AAWD,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,WAElD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,eA8BvC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { KnownCellOutputMimeTypes } from '@curvenote/blocks';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import { SafeOutputs } from './safe';
|
|
5
|
+
import { NativeJupyterOutputs as JupyterOutputs } from './jupyter';
|
|
6
|
+
import { OutputBlock } from './outputBlock';
|
|
7
|
+
const DIRECT_OUTPUT_TYPES = new Set(['stream', 'error']);
|
|
8
|
+
const DIRECT_MIME_TYPES = new Set([
|
|
9
|
+
KnownCellOutputMimeTypes.TextPlain,
|
|
10
|
+
KnownCellOutputMimeTypes.ImagePng,
|
|
11
|
+
KnownCellOutputMimeTypes.ImageGif,
|
|
12
|
+
KnownCellOutputMimeTypes.ImageJpeg,
|
|
13
|
+
KnownCellOutputMimeTypes.ImageBmp,
|
|
14
|
+
]);
|
|
15
|
+
export function allOutputsAreSafe(outputs, directOutputTypes, directMimeTypes) {
|
|
16
|
+
return outputs.reduce((flag, output) => {
|
|
17
|
+
if (directOutputTypes.has(output.output_type))
|
|
18
|
+
return true;
|
|
19
|
+
const data = output.data;
|
|
20
|
+
const mimetypes = data ? Object.keys(data) : [];
|
|
21
|
+
const safe = 'data' in output &&
|
|
22
|
+
Boolean(output.data) &&
|
|
23
|
+
mimetypes.every((mimetype) => directMimeTypes.has(mimetype));
|
|
24
|
+
return flag && safe;
|
|
25
|
+
}, true);
|
|
26
|
+
}
|
|
27
|
+
function listMimetypes(outputs, directOutputTypes) {
|
|
28
|
+
return outputs.map((output) => {
|
|
29
|
+
if (directOutputTypes.has(output.output_type))
|
|
30
|
+
return [output.output_type];
|
|
31
|
+
const data = output.data;
|
|
32
|
+
const mimetypes = data ? Object.keys(data) : [];
|
|
33
|
+
return [output.output_type, mimetypes];
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function anyErrors(outputs) {
|
|
37
|
+
return outputs.reduce((flag, output) => flag || output.output_type === 'error', false);
|
|
38
|
+
}
|
|
39
|
+
export function Output(node) {
|
|
40
|
+
const outputs = node.data;
|
|
41
|
+
const allSafe = allOutputsAreSafe(outputs, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES);
|
|
42
|
+
const hasError = anyErrors(outputs);
|
|
43
|
+
let component;
|
|
44
|
+
if (allSafe) {
|
|
45
|
+
component = _jsx(SafeOutputs, { keyStub: node.key, outputs: outputs });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Hide the iframe if rendering on the server
|
|
49
|
+
component =
|
|
50
|
+
typeof document === 'undefined' ? null : _jsx(JupyterOutputs, { id: node.key, outputs: outputs });
|
|
51
|
+
}
|
|
52
|
+
return (_jsx("figure", Object.assign({ suppressHydrationWarning: !allSafe, id: node.identifier || undefined, className: classNames('max-w-full overflow-auto m-0', {
|
|
53
|
+
'text-left': !node.align || node.align === 'left',
|
|
54
|
+
'text-center': node.align === 'center',
|
|
55
|
+
'text-right': node.align === 'right',
|
|
56
|
+
}) }, { children: _jsx(OutputBlock, Object.assign({ allSafe: allSafe, hasError: hasError }, { children: component })) }), node.key));
|
|
57
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
type Props = {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
allSafe?: boolean;
|
|
5
|
+
hasError?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function OutputBlock(props: Props): JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=outputBlock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outputBlock.d.ts","sourceRoot":"","sources":["../../src/outputBlock.tsx"],"names":[],"mappings":";AAEA,KAAK,KAAK,GAAG;IACX,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,eAWvC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
export function OutputBlock(props) {
|
|
4
|
+
const { children, allSafe, className } = props;
|
|
5
|
+
return (_jsx("div", Object.assign({ suppressHydrationWarning: !allSafe, className: classNames('relative group not-prose overflow-auto mb-4 pl-0.5', className) }, { children: children })));
|
|
6
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { MinifiedOutput } from '@curvenote/nbtx/dist/minify/types';
|
|
3
|
+
export declare function SafeOutputs({ keyStub, outputs }: {
|
|
4
|
+
keyStub: string;
|
|
5
|
+
outputs: MinifiedOutput[];
|
|
6
|
+
}): JSX.Element;
|
|
7
|
+
//# sourceMappingURL=safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe.d.ts","sourceRoot":"","sources":["../../src/safe.tsx"],"names":[],"mappings":";AACA,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,mCAAmC,CAAC;AAwE3C,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,eAM/F"}
|
package/dist/esm/safe.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { KnownCellOutputMimeTypes } from '@curvenote/blocks/dist/blocks/types/jupyter';
|
|
3
|
+
import Stream from './stream';
|
|
4
|
+
import Error from './error';
|
|
5
|
+
import Ansi from 'ansi-to-react';
|
|
6
|
+
/**
|
|
7
|
+
* https://jupyterbook.org/content/code-outputs.html#render-priority
|
|
8
|
+
*
|
|
9
|
+
* nb_render_priority:
|
|
10
|
+
html:
|
|
11
|
+
- "application/vnd.jupyter.widget-view+json"
|
|
12
|
+
- "application/javascript"
|
|
13
|
+
- "text/html"
|
|
14
|
+
- "image/svg+xml"
|
|
15
|
+
- "image/png"
|
|
16
|
+
- "image/jpeg"
|
|
17
|
+
- "text/markdown"
|
|
18
|
+
- "text/latex"
|
|
19
|
+
- "text/plain"
|
|
20
|
+
*/
|
|
21
|
+
const RENDER_PRIORITY = [
|
|
22
|
+
KnownCellOutputMimeTypes.ImagePng,
|
|
23
|
+
KnownCellOutputMimeTypes.ImageJpeg,
|
|
24
|
+
KnownCellOutputMimeTypes.ImageGif,
|
|
25
|
+
KnownCellOutputMimeTypes.ImageBmp,
|
|
26
|
+
];
|
|
27
|
+
function findSafeMimeOutputs(output) {
|
|
28
|
+
const data = output.data;
|
|
29
|
+
const image = RENDER_PRIORITY.reduce((acc, mimetype) => {
|
|
30
|
+
if (acc)
|
|
31
|
+
return acc;
|
|
32
|
+
if (data && data[mimetype])
|
|
33
|
+
return data[mimetype];
|
|
34
|
+
return undefined;
|
|
35
|
+
}, undefined);
|
|
36
|
+
const text = data && data['text/plain'];
|
|
37
|
+
return { image, text };
|
|
38
|
+
}
|
|
39
|
+
function OutputImage({ image, text }) {
|
|
40
|
+
var _a;
|
|
41
|
+
return _jsx("img", { src: image === null || image === void 0 ? void 0 : image.path, alt: (_a = text === null || text === void 0 ? void 0 : text.content) !== null && _a !== void 0 ? _a : 'Image produced in Jupyter' });
|
|
42
|
+
}
|
|
43
|
+
function SafeOutput({ output }) {
|
|
44
|
+
switch (output.output_type) {
|
|
45
|
+
case 'stream':
|
|
46
|
+
return _jsx(Stream, { output: output });
|
|
47
|
+
case 'error':
|
|
48
|
+
return _jsx(Error, { output: output });
|
|
49
|
+
case 'display_data':
|
|
50
|
+
case 'execute_result':
|
|
51
|
+
case 'update_display_data': {
|
|
52
|
+
const { image, text } = findSafeMimeOutputs(output);
|
|
53
|
+
if (!image && !text)
|
|
54
|
+
return null;
|
|
55
|
+
if (image)
|
|
56
|
+
return _jsx(OutputImage, { image: image, text: text });
|
|
57
|
+
if (text)
|
|
58
|
+
return (_jsx("div", { children: _jsx(Ansi, { children: text.content }) }));
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
console.warn(`Unknown output_type ${output['output_type']}`);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function SafeOutputs({ keyStub, outputs }) {
|
|
67
|
+
// TODO better key - add keys during content creation?
|
|
68
|
+
const components = outputs.map((output, idx) => (_jsx(SafeOutput, { output: output }, `${keyStub}-${idx}`)));
|
|
69
|
+
return _jsx(_Fragment, { children: components });
|
|
70
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { HostState } from '@curvenote/connect';
|
|
2
|
+
export interface State {
|
|
3
|
+
app: HostState;
|
|
4
|
+
}
|
|
5
|
+
export declare const selectIFrameHeight: (state: State, id: string) => number | null;
|
|
6
|
+
export declare const selectIFrameReady: (state: State, id: string) => boolean;
|
|
7
|
+
export declare const selectIFrameSendFailed: (state: State, id: string) => false | {
|
|
8
|
+
message: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=selectors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,UAAW,KAAK,MAAM,MAAM,kBACX,CAAC;AAEjD,eAAO,MAAM,iBAAiB,UAAW,KAAK,MAAM,MAAM,YACT,CAAC;AAElD,eAAO,MAAM,sBAAsB,UAAW,KAAK,MAAM,MAAM;;CACb,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { host } from '@curvenote/connect';
|
|
2
|
+
export const selectIFrameHeight = (state, id) => host.selectors.selectIFrameSize(state.app, id);
|
|
3
|
+
export const selectIFrameReady = (state, id) => host.selectors.selectIFrameReady(state.app, id);
|
|
4
|
+
export const selectIFrameSendFailed = (state, id) => host.selectors.selectIFrameFailed(state.app, id);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/stream.tsx"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG5D,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,oBAAoB,CAAA;CAAE,eAY1E"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Ansi from 'ansi-to-react';
|
|
3
|
+
import { ensureString } from '@curvenote/blocks';
|
|
4
|
+
import { MaybeLongContent } from './components';
|
|
5
|
+
export default function Stream({ output }) {
|
|
6
|
+
return (_jsx(MaybeLongContent, { content: ensureString(output.text), path: output.path, render: (content) => (_jsx("pre", Object.assign({ className: "text-sm font-thin font-system" }, { children: _jsx(Ansi, { children: content !== null && content !== void 0 ? content : '' }) }))) }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const MaybeLongContent: ({ content, path, render, }: {
|
|
3
|
+
content?: string | undefined;
|
|
4
|
+
path?: string | undefined;
|
|
5
|
+
render: (content: string) => JSX.Element;
|
|
6
|
+
}) => JSX.Element;
|
|
7
|
+
export declare const DangerousHTML: ({ content, ...rest }: {
|
|
8
|
+
content: string;
|
|
9
|
+
}) => JSX.Element;
|
|
10
|
+
//# sourceMappingURL=components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/components.tsx"],"names":[],"mappings":";AAGA,eAAO,MAAM,gBAAgB;;;sBAOT,MAAM,KAAK,WAAW;iBAUzC,CAAC;AAEF,eAAO,MAAM,aAAa;aAAqC,MAAM;iBAWpE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/error.tsx"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,eAcxE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { MinifiedOutput } from '@curvenote/nbtx/dist/minify/types';
|
|
2
|
+
/**
|
|
3
|
+
* Truncation vs Summarization
|
|
4
|
+
*
|
|
5
|
+
* In Curvespace, we're decided to change our data structure for outputs to align it as
|
|
6
|
+
* closely as possible with Jupyters nbformat.IOutput[] type, but in a way that still allows
|
|
7
|
+
* us to truncate output content and push that to storage.
|
|
8
|
+
*
|
|
9
|
+
* This will be used only in the CLI and Curvespace initially but should be ported back to
|
|
10
|
+
* the rest of the code base. This will mean
|
|
11
|
+
*
|
|
12
|
+
* - changing the DB schema
|
|
13
|
+
* - migration
|
|
14
|
+
* - changing API response
|
|
15
|
+
* - changing the frontend
|
|
16
|
+
* - changing the extension
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
interface LongContent {
|
|
20
|
+
content_type?: string;
|
|
21
|
+
content: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function useLongContent(content?: string, url?: string): {
|
|
24
|
+
data?: LongContent;
|
|
25
|
+
error?: Error;
|
|
26
|
+
};
|
|
27
|
+
export declare function useFetchAnyTruncatedContent(outputs: MinifiedOutput[]): {
|
|
28
|
+
data: ({
|
|
29
|
+
data: {};
|
|
30
|
+
path?: string | undefined;
|
|
31
|
+
traceback: string & string[];
|
|
32
|
+
output_type: "error";
|
|
33
|
+
ename: string;
|
|
34
|
+
evalue: string;
|
|
35
|
+
} | {
|
|
36
|
+
data: {};
|
|
37
|
+
path?: string | undefined;
|
|
38
|
+
output_type: "stream";
|
|
39
|
+
name: import("@jupyterlab/nbformat").StreamType;
|
|
40
|
+
text: import("@jupyterlab/nbformat").MultilineString;
|
|
41
|
+
} | {
|
|
42
|
+
data: {};
|
|
43
|
+
output_type: import("@curvenote/nbtx/dist/minify/types").MimeOutputType;
|
|
44
|
+
execution_count?: import("@jupyterlab/nbformat").ExecutionCount | undefined;
|
|
45
|
+
metadata: import("@lumino/coreutils").PartialJSONObject;
|
|
46
|
+
} | {
|
|
47
|
+
[x: string]: import("@lumino/coreutils").PartialJSONValue | undefined;
|
|
48
|
+
path?: string | undefined;
|
|
49
|
+
traceback: string & string[];
|
|
50
|
+
output_type: "error";
|
|
51
|
+
ename: string;
|
|
52
|
+
evalue: string;
|
|
53
|
+
} | {
|
|
54
|
+
[x: string]: import("@lumino/coreutils").PartialJSONValue | undefined;
|
|
55
|
+
path?: string | undefined;
|
|
56
|
+
output_type: "stream";
|
|
57
|
+
name: import("@jupyterlab/nbformat").StreamType;
|
|
58
|
+
text: import("@jupyterlab/nbformat").MultilineString;
|
|
59
|
+
})[] | undefined;
|
|
60
|
+
error: any;
|
|
61
|
+
};
|
|
62
|
+
export default function useWindowSize(): {
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
};
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,cAAc,EAEf,MAAM,mCAAmC,CAAC;AAI3C;;;;;;;;;;;;;;;;GAgBG;AAEH,UAAU,WAAW;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,cAAc,CAC5B,OAAO,CAAC,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,GACX;IAAE,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAQvC;AAuBD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BpE;AAUD,MAAM,CAAC,OAAO,UAAU,aAAa;;;EAapC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,QAAA,MAAM,gBAAgB;;CAErB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jupyter.d.ts","sourceRoot":"","sources":["../../src/jupyter.tsx"],"names":[],"mappings":";AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQtD,eAAO,MAAM,oBAAoB;QAI3B,MAAM;aACD,cAAc,EAAE;iBAmE1B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { GenericNode } from 'mystjs';
|
|
3
|
+
import type { MinifiedOutput } from '@curvenote/nbtx/dist/minify/types';
|
|
4
|
+
export declare function allOutputsAreSafe(outputs: MinifiedOutput[], directOutputTypes: Set<string>, directMimeTypes: Set<string>): boolean;
|
|
5
|
+
export declare function anyErrors(outputs: MinifiedOutput[]): boolean;
|
|
6
|
+
export declare function Output(node: GenericNode): JSX.Element;
|
|
7
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/output.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAgB5F,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,cAAc,EAAE,EACzB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAY7B;AAWD,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,WAElD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,eA8BvC"}
|