inspect-ai 0.3.81__py3-none-any.whl → 0.3.82__py3-none-any.whl
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.
- inspect_ai/_cli/eval.py +35 -2
- inspect_ai/_cli/util.py +44 -1
- inspect_ai/_display/core/config.py +1 -1
- inspect_ai/_display/core/display.py +13 -4
- inspect_ai/_display/core/results.py +1 -1
- inspect_ai/_display/textual/widgets/task_detail.py +5 -4
- inspect_ai/_eval/eval.py +38 -1
- inspect_ai/_eval/evalset.py +5 -0
- inspect_ai/_eval/run.py +5 -2
- inspect_ai/_eval/task/log.py +53 -6
- inspect_ai/_eval/task/run.py +51 -10
- inspect_ai/_util/constants.py +2 -0
- inspect_ai/_util/file.py +17 -1
- inspect_ai/_util/json.py +36 -1
- inspect_ai/_view/server.py +113 -1
- inspect_ai/_view/www/App.css +1 -1
- inspect_ai/_view/www/dist/assets/index.css +518 -296
- inspect_ai/_view/www/dist/assets/index.js +38803 -36307
- inspect_ai/_view/www/eslint.config.mjs +1 -1
- inspect_ai/_view/www/log-schema.json +13 -0
- inspect_ai/_view/www/node_modules/flatted/python/flatted.py +149 -0
- inspect_ai/_view/www/package.json +8 -2
- inspect_ai/_view/www/src/App.tsx +151 -855
- inspect_ai/_view/www/src/api/api-browser.ts +176 -5
- inspect_ai/_view/www/src/api/api-vscode.ts +75 -1
- inspect_ai/_view/www/src/api/client-api.ts +66 -10
- inspect_ai/_view/www/src/api/jsonrpc.ts +2 -0
- inspect_ai/_view/www/src/api/types.ts +107 -2
- inspect_ai/_view/www/src/appearance/icons.ts +1 -0
- inspect_ai/_view/www/src/components/AsciinemaPlayer.tsx +3 -3
- inspect_ai/_view/www/src/components/DownloadPanel.tsx +2 -2
- inspect_ai/_view/www/src/components/ExpandablePanel.tsx +56 -61
- inspect_ai/_view/www/src/components/FindBand.tsx +17 -9
- inspect_ai/_view/www/src/components/HumanBaselineView.tsx +1 -1
- inspect_ai/_view/www/src/components/JsonPanel.tsx +14 -24
- inspect_ai/_view/www/src/components/LargeModal.tsx +2 -35
- inspect_ai/_view/www/src/components/LightboxCarousel.tsx +27 -11
- inspect_ai/_view/www/src/components/LiveVirtualList.module.css +11 -0
- inspect_ai/_view/www/src/components/LiveVirtualList.tsx +177 -0
- inspect_ai/_view/www/src/components/MarkdownDiv.tsx +3 -3
- inspect_ai/_view/www/src/components/MessageBand.tsx +14 -9
- inspect_ai/_view/www/src/components/MorePopOver.tsx +3 -3
- inspect_ai/_view/www/src/components/NavPills.tsx +20 -8
- inspect_ai/_view/www/src/components/NoContentsPanel.module.css +12 -0
- inspect_ai/_view/www/src/components/NoContentsPanel.tsx +20 -0
- inspect_ai/_view/www/src/components/ProgressBar.module.css +5 -4
- inspect_ai/_view/www/src/components/ProgressBar.tsx +3 -2
- inspect_ai/_view/www/src/components/PulsingDots.module.css +81 -0
- inspect_ai/_view/www/src/components/PulsingDots.tsx +45 -0
- inspect_ai/_view/www/src/components/TabSet.tsx +4 -37
- inspect_ai/_view/www/src/components/ToolButton.tsx +3 -4
- inspect_ai/_view/www/src/index.tsx +26 -94
- inspect_ai/_view/www/src/logfile/remoteLogFile.ts +9 -1
- inspect_ai/_view/www/src/logfile/remoteZipFile.ts +30 -4
- inspect_ai/_view/www/src/metadata/RenderedContent.tsx +4 -6
- inspect_ai/_view/www/src/plan/ScorerDetailView.tsx +1 -1
- inspect_ai/_view/www/src/samples/InlineSampleDisplay.module.css +9 -1
- inspect_ai/_view/www/src/samples/InlineSampleDisplay.tsx +67 -28
- inspect_ai/_view/www/src/samples/SampleDialog.tsx +51 -22
- inspect_ai/_view/www/src/samples/SampleDisplay.module.css +4 -0
- inspect_ai/_view/www/src/samples/SampleDisplay.tsx +144 -90
- inspect_ai/_view/www/src/samples/SampleSummaryView.module.css +4 -0
- inspect_ai/_view/www/src/samples/SampleSummaryView.tsx +82 -35
- inspect_ai/_view/www/src/samples/SamplesTools.tsx +23 -30
- inspect_ai/_view/www/src/samples/chat/ChatMessage.tsx +2 -1
- inspect_ai/_view/www/src/samples/chat/ChatMessageRenderer.tsx +1 -1
- inspect_ai/_view/www/src/samples/chat/ChatViewVirtualList.tsx +45 -53
- inspect_ai/_view/www/src/samples/chat/MessageContent.tsx +4 -1
- inspect_ai/_view/www/src/samples/chat/MessageContents.tsx +3 -0
- inspect_ai/_view/www/src/samples/chat/messages.ts +34 -0
- inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.module.css +3 -0
- inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.tsx +10 -1
- inspect_ai/_view/www/src/samples/chat/tools/ToolInput.tsx +22 -46
- inspect_ai/_view/www/src/samples/descriptor/samplesDescriptor.tsx +25 -17
- inspect_ai/_view/www/src/samples/descriptor/score/ObjectScoreDescriptor.tsx +2 -1
- inspect_ai/_view/www/src/samples/descriptor/types.ts +6 -5
- inspect_ai/_view/www/src/samples/list/SampleFooter.module.css +21 -3
- inspect_ai/_view/www/src/samples/list/SampleFooter.tsx +20 -1
- inspect_ai/_view/www/src/samples/list/SampleList.tsx +105 -85
- inspect_ai/_view/www/src/samples/list/SampleRow.module.css +6 -0
- inspect_ai/_view/www/src/samples/list/SampleRow.tsx +27 -14
- inspect_ai/_view/www/src/samples/sample-tools/SelectScorer.tsx +29 -18
- inspect_ai/_view/www/src/samples/sample-tools/SortFilter.tsx +28 -28
- inspect_ai/_view/www/src/samples/sample-tools/sample-filter/SampleFilter.tsx +19 -9
- inspect_ai/_view/www/src/samples/sampleDataAdapter.ts +33 -0
- inspect_ai/_view/www/src/samples/sampleLimit.ts +2 -2
- inspect_ai/_view/www/src/samples/scores/SampleScoreView.tsx +7 -9
- inspect_ai/_view/www/src/samples/scores/SampleScores.tsx +7 -11
- inspect_ai/_view/www/src/samples/transcript/ErrorEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/InfoEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/InputEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/ModelEventView.module.css +4 -0
- inspect_ai/_view/www/src/samples/transcript/ModelEventView.tsx +10 -24
- inspect_ai/_view/www/src/samples/transcript/SampleInitEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/SampleLimitEventView.tsx +4 -22
- inspect_ai/_view/www/src/samples/transcript/SandboxEventView.tsx +15 -24
- inspect_ai/_view/www/src/samples/transcript/ScoreEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/StepEventView.tsx +6 -28
- inspect_ai/_view/www/src/samples/transcript/SubtaskEventView.tsx +24 -34
- inspect_ai/_view/www/src/samples/transcript/ToolEventView.module.css +4 -0
- inspect_ai/_view/www/src/samples/transcript/ToolEventView.tsx +8 -13
- inspect_ai/_view/www/src/samples/transcript/TranscriptView.tsx +197 -338
- inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.module.css +16 -0
- inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.tsx +44 -0
- inspect_ai/_view/www/src/samples/transcript/event/EventNav.tsx +7 -4
- inspect_ai/_view/www/src/samples/transcript/event/EventPanel.tsx +52 -58
- inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.module.css +23 -0
- inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.tsx +27 -0
- inspect_ai/_view/www/src/samples/transcript/state/StateEventRenderers.tsx +30 -1
- inspect_ai/_view/www/src/samples/transcript/state/StateEventView.tsx +102 -72
- inspect_ai/_view/www/src/scoring/utils.ts +87 -0
- inspect_ai/_view/www/src/state/appSlice.ts +244 -0
- inspect_ai/_view/www/src/state/hooks.ts +397 -0
- inspect_ai/_view/www/src/state/logPolling.ts +196 -0
- inspect_ai/_view/www/src/state/logSlice.ts +214 -0
- inspect_ai/_view/www/src/state/logsPolling.ts +118 -0
- inspect_ai/_view/www/src/state/logsSlice.ts +181 -0
- inspect_ai/_view/www/src/state/samplePolling.ts +311 -0
- inspect_ai/_view/www/src/state/sampleSlice.ts +127 -0
- inspect_ai/_view/www/src/state/sampleUtils.ts +21 -0
- inspect_ai/_view/www/src/state/scrolling.ts +206 -0
- inspect_ai/_view/www/src/state/store.ts +168 -0
- inspect_ai/_view/www/src/state/store_filter.ts +84 -0
- inspect_ai/_view/www/src/state/utils.ts +23 -0
- inspect_ai/_view/www/src/storage/index.ts +26 -0
- inspect_ai/_view/www/src/types/log.d.ts +2 -0
- inspect_ai/_view/www/src/types.ts +94 -32
- inspect_ai/_view/www/src/utils/attachments.ts +58 -23
- inspect_ai/_view/www/src/utils/logger.ts +52 -0
- inspect_ai/_view/www/src/utils/polling.ts +100 -0
- inspect_ai/_view/www/src/utils/react.ts +30 -0
- inspect_ai/_view/www/src/utils/vscode.ts +1 -1
- inspect_ai/_view/www/src/workspace/WorkSpace.tsx +181 -216
- inspect_ai/_view/www/src/workspace/WorkSpaceView.tsx +11 -53
- inspect_ai/_view/www/src/workspace/navbar/Navbar.tsx +8 -18
- inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.module.css +1 -0
- inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.tsx +40 -22
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.module.css +0 -1
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.tsx +98 -39
- inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.module.css +32 -0
- inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.tsx +32 -0
- inspect_ai/_view/www/src/workspace/navbar/SecondaryBar.tsx +11 -13
- inspect_ai/_view/www/src/workspace/navbar/StatusPanel.tsx +6 -2
- inspect_ai/_view/www/src/workspace/sidebar/LogDirectoryTitleView.tsx +4 -4
- inspect_ai/_view/www/src/workspace/sidebar/Sidebar.tsx +28 -13
- inspect_ai/_view/www/src/workspace/tabs/InfoTab.tsx +5 -10
- inspect_ai/_view/www/src/workspace/tabs/JsonTab.tsx +4 -4
- inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.module.css +22 -0
- inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.tsx +19 -0
- inspect_ai/_view/www/src/workspace/tabs/SamplesTab.tsx +110 -115
- inspect_ai/_view/www/src/workspace/tabs/grouping.ts +37 -5
- inspect_ai/_view/www/src/workspace/tabs/types.ts +4 -0
- inspect_ai/_view/www/src/workspace/types.ts +4 -3
- inspect_ai/_view/www/src/workspace/utils.ts +4 -4
- inspect_ai/_view/www/vite.config.js +6 -0
- inspect_ai/_view/www/yarn.lock +370 -354
- inspect_ai/log/_condense.py +26 -0
- inspect_ai/log/_log.py +6 -3
- inspect_ai/log/_recorders/buffer/__init__.py +14 -0
- inspect_ai/log/_recorders/buffer/buffer.py +30 -0
- inspect_ai/log/_recorders/buffer/database.py +685 -0
- inspect_ai/log/_recorders/buffer/filestore.py +259 -0
- inspect_ai/log/_recorders/buffer/types.py +84 -0
- inspect_ai/log/_recorders/eval.py +2 -11
- inspect_ai/log/_recorders/types.py +30 -0
- inspect_ai/log/_transcript.py +27 -1
- inspect_ai/model/_call_tools.py +1 -0
- inspect_ai/model/_generate_config.py +2 -2
- inspect_ai/model/_model.py +1 -0
- inspect_ai/tool/_tool_support_helpers.py +4 -4
- inspect_ai/tool/_tools/_web_browser/_web_browser.py +3 -1
- inspect_ai/util/_subtask.py +1 -0
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/METADATA +1 -1
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/RECORD +178 -138
- inspect_ai/_view/www/src/samples/transcript/SampleTranscript.tsx +0 -22
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/licenses/LICENSE +0 -0
- {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.82.dist-info}/top_level.txt +0 -0
@@ -2,17 +2,19 @@ import clsx from "clsx";
|
|
2
2
|
import {
|
3
3
|
CSSProperties,
|
4
4
|
FC,
|
5
|
+
memo,
|
5
6
|
ReactNode,
|
6
7
|
useCallback,
|
7
|
-
useEffect,
|
8
8
|
useRef,
|
9
9
|
useState,
|
10
10
|
} from "react";
|
11
11
|
import { ApplicationIcons } from "../appearance/icons";
|
12
|
+
import { useCollapsedState } from "../state/hooks";
|
12
13
|
import { useResizeObserver } from "../utils/dom";
|
13
14
|
import "./ExpandablePanel.css";
|
14
15
|
|
15
16
|
interface ExpandablePanelProps {
|
17
|
+
id: string;
|
16
18
|
collapse: boolean;
|
17
19
|
border?: boolean;
|
18
20
|
lines?: number;
|
@@ -20,72 +22,64 @@ interface ExpandablePanelProps {
|
|
20
22
|
className?: string | string[];
|
21
23
|
}
|
22
24
|
|
23
|
-
export const ExpandablePanel: FC<ExpandablePanelProps> = (
|
24
|
-
collapse,
|
25
|
-
|
26
|
-
lines = 15,
|
27
|
-
children,
|
28
|
-
className,
|
29
|
-
}) => {
|
30
|
-
const [isCollapsed, setIsCollapsed] = useState(collapse);
|
31
|
-
const [showToggle, setShowToggle] = useState(false);
|
32
|
-
const lineHeightRef = useRef<number>(0);
|
25
|
+
export const ExpandablePanel: FC<ExpandablePanelProps> = memo(
|
26
|
+
({ id, collapse, border, lines = 15, children, className }) => {
|
27
|
+
const [collapsed, setCollapsed] = useCollapsedState(id, collapse);
|
33
28
|
|
34
|
-
|
35
|
-
|
36
|
-
}, [collapse]);
|
29
|
+
const [showToggle, setShowToggle] = useState(false);
|
30
|
+
const lineHeightRef = useRef<number>(0);
|
37
31
|
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
const checkOverflow = useCallback(
|
33
|
+
(entry: ResizeObserverEntry) => {
|
34
|
+
const element = entry.target as HTMLDivElement;
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
// Calculate line height if we haven't yet
|
37
|
+
if (!lineHeightRef.current) {
|
38
|
+
const computedStyle = window.getComputedStyle(element);
|
39
|
+
lineHeightRef.current = parseInt(computedStyle.lineHeight) || 16; // fallback to 16px if can't get line height
|
40
|
+
}
|
47
41
|
|
48
|
-
|
49
|
-
|
42
|
+
const maxCollapsedHeight = lines * lineHeightRef.current;
|
43
|
+
const contentHeight = element.scrollHeight;
|
50
44
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
setShowToggle(contentHeight > maxCollapsedHeight);
|
46
|
+
},
|
47
|
+
[lines],
|
48
|
+
);
|
49
|
+
const contentRef = useResizeObserver(checkOverflow);
|
55
50
|
|
56
|
-
|
51
|
+
const baseStyles = {
|
52
|
+
overflow: "hidden",
|
53
|
+
...(collapsed && {
|
54
|
+
maxHeight: `${lines}em`,
|
55
|
+
}),
|
56
|
+
};
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
return (
|
59
|
+
<div className={clsx(className)}>
|
60
|
+
<div
|
61
|
+
style={baseStyles}
|
62
|
+
ref={contentRef}
|
63
|
+
className={clsx(
|
64
|
+
"expandable-panel",
|
65
|
+
collapsed ? "expandable-collapsed" : undefined,
|
66
|
+
border ? "expandable-bordered" : undefined,
|
67
|
+
)}
|
68
|
+
>
|
69
|
+
{children}
|
70
|
+
</div>
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
"expandable-panel",
|
72
|
-
isCollapsed ? "expandable-collapsed" : undefined,
|
73
|
-
border ? "expandable-bordered" : undefined,
|
72
|
+
{showToggle && (
|
73
|
+
<MoreToggle
|
74
|
+
collapsed={collapsed}
|
75
|
+
setCollapsed={setCollapsed}
|
76
|
+
border={!border}
|
77
|
+
/>
|
74
78
|
)}
|
75
|
-
>
|
76
|
-
{children}
|
77
79
|
</div>
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
collapsed={isCollapsed}
|
82
|
-
setCollapsed={setIsCollapsed}
|
83
|
-
border={!border}
|
84
|
-
/>
|
85
|
-
)}
|
86
|
-
</div>
|
87
|
-
);
|
88
|
-
};
|
80
|
+
);
|
81
|
+
},
|
82
|
+
);
|
89
83
|
|
90
84
|
interface MoreToggleProps {
|
91
85
|
collapsed: boolean;
|
@@ -105,13 +99,14 @@ const MoreToggle: FC<MoreToggleProps> = ({
|
|
105
99
|
? ApplicationIcons["expand-down"]
|
106
100
|
: ApplicationIcons.collapse.up;
|
107
101
|
|
102
|
+
const handleClick = useCallback(() => {
|
103
|
+
setCollapsed(!collapsed);
|
104
|
+
}, [setCollapsed, collapsed]);
|
105
|
+
|
108
106
|
return (
|
109
107
|
<div className={`more-toggle ${border ? "bordered" : ""}`} style={style}>
|
110
108
|
<div className="more-toggle-container">
|
111
|
-
<button
|
112
|
-
className="btn more-toggle-button"
|
113
|
-
onClick={() => setCollapsed(!collapsed)}
|
114
|
-
>
|
109
|
+
<button className="btn more-toggle-button" onClick={handleClick}>
|
115
110
|
<i className={icon} />
|
116
111
|
{text}
|
117
112
|
</button>
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import { FC, KeyboardEvent, useCallback, useEffect, useRef } from "react";
|
2
2
|
import { ApplicationIcons } from "../appearance/icons";
|
3
|
+
import { useStore } from "../state/store";
|
3
4
|
import "./FindBand.css";
|
4
5
|
|
5
|
-
interface FindBandProps {
|
6
|
-
hideBand: () => void;
|
7
|
-
}
|
6
|
+
interface FindBandProps {}
|
8
7
|
|
9
|
-
export const FindBand: FC<FindBandProps> = (
|
8
|
+
export const FindBand: FC<FindBandProps> = () => {
|
10
9
|
const searchBoxRef = useRef<HTMLInputElement>(null);
|
10
|
+
const storeHideFind = useStore((state) => state.appActions.hideFind);
|
11
11
|
|
12
12
|
useEffect(() => {
|
13
13
|
setTimeout(() => {
|
@@ -84,14 +84,22 @@ export const FindBand: FC<FindBandProps> = ({ hideBand }) => {
|
|
84
84
|
const handleKeyDown = useCallback(
|
85
85
|
(e: KeyboardEvent<HTMLInputElement>) => {
|
86
86
|
if (e.key === "Escape") {
|
87
|
-
|
87
|
+
storeHideFind();
|
88
88
|
} else if (e.key === "Enter") {
|
89
89
|
handleSearch(false);
|
90
90
|
}
|
91
91
|
},
|
92
|
-
[
|
92
|
+
[storeHideFind, handleSearch],
|
93
93
|
);
|
94
94
|
|
95
|
+
const showSearch = useCallback(() => {
|
96
|
+
handleSearch(true);
|
97
|
+
}, [handleSearch]);
|
98
|
+
|
99
|
+
const hideSearch = useCallback(() => {
|
100
|
+
handleSearch(false);
|
101
|
+
}, [handleSearch]);
|
102
|
+
|
95
103
|
return (
|
96
104
|
<div className="findBand">
|
97
105
|
<input
|
@@ -105,7 +113,7 @@ export const FindBand: FC<FindBandProps> = ({ hideBand }) => {
|
|
105
113
|
type="button"
|
106
114
|
title="Previous match"
|
107
115
|
className="btn next"
|
108
|
-
onClick={
|
116
|
+
onClick={showSearch}
|
109
117
|
>
|
110
118
|
<i className={ApplicationIcons.arrows.up} />
|
111
119
|
</button>
|
@@ -113,7 +121,7 @@ export const FindBand: FC<FindBandProps> = ({ hideBand }) => {
|
|
113
121
|
type="button"
|
114
122
|
title="Next match"
|
115
123
|
className="btn prev"
|
116
|
-
onClick={
|
124
|
+
onClick={hideSearch}
|
117
125
|
>
|
118
126
|
<i className={ApplicationIcons.arrows.down} />
|
119
127
|
</button>
|
@@ -121,7 +129,7 @@ export const FindBand: FC<FindBandProps> = ({ hideBand }) => {
|
|
121
129
|
type="button"
|
122
130
|
title="Close"
|
123
131
|
className="btn close"
|
124
|
-
onClick={
|
132
|
+
onClick={storeHideFind}
|
125
133
|
>
|
126
134
|
<i className={ApplicationIcons.close} />
|
127
135
|
</button>
|
@@ -133,7 +133,7 @@ export const HumanBaselineView: FC<HumanBaselineViewProps> = ({
|
|
133
133
|
/>
|
134
134
|
</div>
|
135
135
|
<div className={"asciinema-body"}>
|
136
|
-
<LightboxCarousel slides={player_fns} />
|
136
|
+
<LightboxCarousel id="ascii-cinema" slides={player_fns} />
|
137
137
|
</div>
|
138
138
|
</div>
|
139
139
|
</div>
|
@@ -1,20 +1,18 @@
|
|
1
1
|
import clsx from "clsx";
|
2
|
-
import {
|
3
|
-
import
|
2
|
+
import { CSSProperties, FC, useMemo } from "react";
|
3
|
+
import { usePrismHighlight } from "../state/hooks";
|
4
4
|
import "./JsonPanel.css";
|
5
5
|
|
6
|
-
const kPrismRenderMaxSize = 250000;
|
7
|
-
|
8
6
|
interface JSONPanelProps {
|
9
7
|
id?: string;
|
10
8
|
data?: unknown;
|
11
9
|
json?: string;
|
12
10
|
simple?: boolean;
|
13
|
-
style?:
|
11
|
+
style?: CSSProperties;
|
14
12
|
className?: string | string[];
|
15
13
|
}
|
16
14
|
|
17
|
-
export const JSONPanel:
|
15
|
+
export const JSONPanel: FC<JSONPanelProps> = ({
|
18
16
|
id,
|
19
17
|
json,
|
20
18
|
data,
|
@@ -22,30 +20,22 @@ export const JSONPanel: React.FC<JSONPanelProps> = ({
|
|
22
20
|
style,
|
23
21
|
className,
|
24
22
|
}) => {
|
25
|
-
const codeRef = useRef<HTMLElement>(null);
|
26
23
|
const sourceCode = useMemo(() => {
|
27
24
|
return json || JSON.stringify(resolveBase64(data), undefined, 2);
|
28
25
|
}, [json, data]);
|
29
|
-
|
30
|
-
useEffect(() => {
|
31
|
-
if (sourceCode.length < kPrismRenderMaxSize && codeRef.current) {
|
32
|
-
highlightElement(codeRef.current);
|
33
|
-
}
|
34
|
-
}, [sourceCode]);
|
26
|
+
const prismParentRef = usePrismHighlight(sourceCode);
|
35
27
|
|
36
28
|
return (
|
37
|
-
<
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
<code
|
42
|
-
id={id}
|
43
|
-
ref={codeRef}
|
44
|
-
className={clsx("source-code", "language-javascript")}
|
29
|
+
<div ref={prismParentRef}>
|
30
|
+
<pre
|
31
|
+
className={clsx("json-panel", simple ? "simple" : "", className)}
|
32
|
+
style={style}
|
45
33
|
>
|
46
|
-
{
|
47
|
-
|
48
|
-
|
34
|
+
<code id={id} className={clsx("source-code", "language-javascript")}>
|
35
|
+
{sourceCode}
|
36
|
+
</code>
|
37
|
+
</pre>
|
38
|
+
</div>
|
49
39
|
);
|
50
40
|
};
|
51
41
|
|
@@ -1,15 +1,7 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import { ProgressBar } from "./ProgressBar";
|
3
3
|
|
4
|
-
import {
|
5
|
-
FC,
|
6
|
-
ReactNode,
|
7
|
-
RefObject,
|
8
|
-
UIEvent,
|
9
|
-
useCallback,
|
10
|
-
useEffect,
|
11
|
-
useRef,
|
12
|
-
} from "react";
|
4
|
+
import { FC, ReactNode, RefObject, useRef } from "react";
|
13
5
|
import styles from "./LargeModal.module.css";
|
14
6
|
|
15
7
|
export interface ModalTool {
|
@@ -35,8 +27,6 @@ interface LargeModalProps {
|
|
35
27
|
onkeyup: (e: any) => void;
|
36
28
|
onHide: () => void;
|
37
29
|
scrollRef: RefObject<HTMLDivElement | null>;
|
38
|
-
initialScrollPositionRef: RefObject<number>;
|
39
|
-
setInitialScrollPosition: (position: number) => void;
|
40
30
|
children: ReactNode;
|
41
31
|
}
|
42
32
|
|
@@ -51,8 +41,6 @@ export const LargeModal: FC<LargeModalProps> = ({
|
|
51
41
|
visible,
|
52
42
|
onHide,
|
53
43
|
showProgress,
|
54
|
-
initialScrollPositionRef,
|
55
|
-
setInitialScrollPosition,
|
56
44
|
scrollRef,
|
57
45
|
}) => {
|
58
46
|
// The footer
|
@@ -67,27 +55,6 @@ export const LargeModal: FC<LargeModalProps> = ({
|
|
67
55
|
const modalRef = useRef(null);
|
68
56
|
scrollRef = scrollRef || modalRef;
|
69
57
|
|
70
|
-
useEffect(() => {
|
71
|
-
if (scrollRef.current) {
|
72
|
-
setTimeout(() => {
|
73
|
-
if (
|
74
|
-
scrollRef.current &&
|
75
|
-
initialScrollPositionRef.current &&
|
76
|
-
scrollRef.current.scrollTop !== initialScrollPositionRef?.current
|
77
|
-
) {
|
78
|
-
scrollRef.current.scrollTop = initialScrollPositionRef.current;
|
79
|
-
}
|
80
|
-
}, 0);
|
81
|
-
}
|
82
|
-
}, []);
|
83
|
-
|
84
|
-
const onScroll = useCallback(
|
85
|
-
(e: UIEvent<HTMLDivElement>) => {
|
86
|
-
setInitialScrollPosition(e.currentTarget.scrollTop);
|
87
|
-
},
|
88
|
-
[setInitialScrollPosition],
|
89
|
-
);
|
90
|
-
|
91
58
|
return (
|
92
59
|
<div
|
93
60
|
id={id}
|
@@ -149,7 +116,7 @@ export const LargeModal: FC<LargeModalProps> = ({
|
|
149
116
|
</button>
|
150
117
|
</div>
|
151
118
|
<ProgressBar animating={showProgress} />
|
152
|
-
<div className={"modal-body"} ref={scrollRef}
|
119
|
+
<div className={"modal-body"} ref={scrollRef}>
|
153
120
|
{children}
|
154
121
|
</div>
|
155
122
|
{modalFooter}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import clsx from "clsx";
|
2
|
-
import { FC, ReactNode, useCallback, useEffect
|
2
|
+
import { FC, MouseEvent, ReactNode, useCallback, useEffect } from "react";
|
3
3
|
import { ApplicationIcons } from "../appearance/icons";
|
4
|
+
import { useProperty } from "../state/hooks";
|
4
5
|
import styles from "./LightboxCarousel.module.css";
|
5
6
|
|
6
7
|
interface Slide {
|
@@ -9,16 +10,25 @@ interface Slide {
|
|
9
10
|
}
|
10
11
|
|
11
12
|
interface LightboxCarouselProps {
|
13
|
+
id: string;
|
12
14
|
slides: Slide[];
|
13
15
|
}
|
14
16
|
|
15
17
|
/**
|
16
18
|
* LightboxCarousel component provides a carousel with lightbox functionality.
|
17
19
|
*/
|
18
|
-
export const LightboxCarousel: FC<LightboxCarouselProps> = ({ slides }) => {
|
19
|
-
const [isOpen, setIsOpen] =
|
20
|
-
|
21
|
-
|
20
|
+
export const LightboxCarousel: FC<LightboxCarouselProps> = ({ id, slides }) => {
|
21
|
+
const [isOpen, setIsOpen] = useProperty(id, "isOpen", {
|
22
|
+
defaultValue: false,
|
23
|
+
});
|
24
|
+
|
25
|
+
const [currentIndex, setCurrentIndex] = useProperty(id, "currentIndex", {
|
26
|
+
defaultValue: 0,
|
27
|
+
});
|
28
|
+
|
29
|
+
const [showOverlay, setShowOverlay] = useProperty(id, "showOverlay", {
|
30
|
+
defaultValue: false,
|
31
|
+
});
|
22
32
|
|
23
33
|
const openLightbox = useCallback(
|
24
34
|
(index: number) => {
|
@@ -28,7 +38,7 @@ export const LightboxCarousel: FC<LightboxCarouselProps> = ({ slides }) => {
|
|
28
38
|
// Slight delay before setting isOpen so the fade-in starts from opacity: 0
|
29
39
|
setTimeout(() => setIsOpen(true), 10);
|
30
40
|
},
|
31
|
-
[
|
41
|
+
[setIsOpen],
|
32
42
|
);
|
33
43
|
|
34
44
|
const closeLightbox = useCallback(() => {
|
@@ -46,13 +56,11 @@ export const LightboxCarousel: FC<LightboxCarouselProps> = ({ slides }) => {
|
|
46
56
|
}, [isOpen, showOverlay, setShowOverlay]);
|
47
57
|
|
48
58
|
const showNext = useCallback(() => {
|
49
|
-
setCurrentIndex(
|
50
|
-
return (prev + 1) % slides.length;
|
51
|
-
});
|
59
|
+
setCurrentIndex(currentIndex + 1);
|
52
60
|
}, [slides, setCurrentIndex]);
|
53
61
|
|
54
62
|
const showPrev = useCallback(() => {
|
55
|
-
setCurrentIndex((
|
63
|
+
setCurrentIndex((currentIndex - 1 + slides.length) % slides.length);
|
56
64
|
}, [slides, setCurrentIndex]);
|
57
65
|
|
58
66
|
// Keyboard Navigation
|
@@ -73,6 +81,13 @@ export const LightboxCarousel: FC<LightboxCarouselProps> = ({ slides }) => {
|
|
73
81
|
return () => window.removeEventListener("keyup", handleKeyUp);
|
74
82
|
}, [isOpen, showNext, showPrev]);
|
75
83
|
|
84
|
+
const handleThumbClick = useCallback(
|
85
|
+
(e: MouseEvent<HTMLDivElement>) => {
|
86
|
+
const index = Number((e.currentTarget as HTMLDivElement).dataset.index);
|
87
|
+
openLightbox(index);
|
88
|
+
},
|
89
|
+
[openLightbox],
|
90
|
+
);
|
76
91
|
return (
|
77
92
|
<div className={clsx("lightbox-carousel-container")}>
|
78
93
|
<div className={clsx(styles.carouselThumbs)}>
|
@@ -80,8 +95,9 @@ export const LightboxCarousel: FC<LightboxCarouselProps> = ({ slides }) => {
|
|
80
95
|
return (
|
81
96
|
<div
|
82
97
|
key={index}
|
98
|
+
data-index={index}
|
83
99
|
className={clsx(styles.carouselThumb)}
|
84
|
-
onClick={
|
100
|
+
onClick={handleThumbClick}
|
85
101
|
>
|
86
102
|
<div>{slide.label}</div>
|
87
103
|
<div>
|
@@ -0,0 +1,177 @@
|
|
1
|
+
import clsx from "clsx";
|
2
|
+
import {
|
3
|
+
ReactNode,
|
4
|
+
RefObject,
|
5
|
+
useCallback,
|
6
|
+
useEffect,
|
7
|
+
useRef,
|
8
|
+
useState,
|
9
|
+
} from "react";
|
10
|
+
import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
|
11
|
+
import { usePrevious, useProperty } from "../state/hooks";
|
12
|
+
import { useRafThrottle, useVirtuosoState } from "../state/scrolling";
|
13
|
+
import { PulsingDots } from "./PulsingDots";
|
14
|
+
|
15
|
+
import styles from "./LiveVirtualList.module.css";
|
16
|
+
|
17
|
+
interface LiveVirtualListProps<T> {
|
18
|
+
id: string;
|
19
|
+
className?: string | string[];
|
20
|
+
|
21
|
+
// The scroll ref to use for the virtual list
|
22
|
+
scrollRef?: RefObject<HTMLDivElement | null>;
|
23
|
+
|
24
|
+
// The data and rendering function for the data
|
25
|
+
data: T[];
|
26
|
+
renderRow: (index: number, item: T) => ReactNode;
|
27
|
+
|
28
|
+
// Whether the virtual list is live (controls its follow
|
29
|
+
// behavior)
|
30
|
+
live?: boolean;
|
31
|
+
|
32
|
+
// The progress message to show (if any)
|
33
|
+
// no message show if progress isn't provided
|
34
|
+
showProgress?: boolean;
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Renders the Transcript component.
|
39
|
+
*/
|
40
|
+
export const LiveVirtualList = <T,>({
|
41
|
+
id,
|
42
|
+
className,
|
43
|
+
data,
|
44
|
+
renderRow,
|
45
|
+
scrollRef,
|
46
|
+
live,
|
47
|
+
showProgress,
|
48
|
+
}: LiveVirtualListProps<T>) => {
|
49
|
+
// The list handle and list state management
|
50
|
+
const listHandle = useRef<VirtuosoHandle>(null);
|
51
|
+
const { getRestoreState, isScrolling } = useVirtuosoState(
|
52
|
+
listHandle,
|
53
|
+
`live-virtual-list-${id}`,
|
54
|
+
);
|
55
|
+
|
56
|
+
// Track whether we're following output
|
57
|
+
const [followOutput, setFollowOutput] = useProperty<boolean | null>(
|
58
|
+
id,
|
59
|
+
"follow",
|
60
|
+
{
|
61
|
+
defaultValue: null,
|
62
|
+
},
|
63
|
+
);
|
64
|
+
const isAutoScrollingRef = useRef(false);
|
65
|
+
|
66
|
+
// Only we first load set the defaul value for following
|
67
|
+
// based upon whether or not the transcript is 'live'
|
68
|
+
useEffect(() => {
|
69
|
+
if (followOutput === null) {
|
70
|
+
setFollowOutput(!!live);
|
71
|
+
}
|
72
|
+
}, []);
|
73
|
+
|
74
|
+
// Track whether we were previously running so we can
|
75
|
+
// decide whether to pop up to the top
|
76
|
+
const prevLive = usePrevious(live);
|
77
|
+
useEffect(() => {
|
78
|
+
// When we finish running, if we are following output
|
79
|
+
// then scroll up to the top
|
80
|
+
if (!live && prevLive && followOutput && scrollRef?.current) {
|
81
|
+
setFollowOutput(false);
|
82
|
+
setTimeout(() => {
|
83
|
+
if (scrollRef.current) {
|
84
|
+
scrollRef.current.scrollTo({ top: 0, behavior: "instant" });
|
85
|
+
}
|
86
|
+
}, 100);
|
87
|
+
}
|
88
|
+
}, [live, followOutput]);
|
89
|
+
|
90
|
+
const handleScroll = useRafThrottle(() => {
|
91
|
+
// Skip processing if auto-scrolling is in progress
|
92
|
+
if (isAutoScrollingRef.current) return;
|
93
|
+
|
94
|
+
// If we're not running, don't mess with auto scrolling
|
95
|
+
if (!live) return;
|
96
|
+
|
97
|
+
// Make the bottom start following
|
98
|
+
if (scrollRef?.current && listHandle.current) {
|
99
|
+
const parent = scrollRef.current;
|
100
|
+
const isAtBottom =
|
101
|
+
parent.scrollHeight - parent.scrollTop <= parent.clientHeight + 30;
|
102
|
+
|
103
|
+
if (isAtBottom && !followOutput) {
|
104
|
+
setFollowOutput(true);
|
105
|
+
} else if (!isAtBottom && followOutput) {
|
106
|
+
setFollowOutput(false);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}, [setFollowOutput, followOutput, live]);
|
110
|
+
|
111
|
+
const heightChanged = useCallback(
|
112
|
+
(height: number) => {
|
113
|
+
requestAnimationFrame(() => {
|
114
|
+
if (followOutput && live && scrollRef?.current) {
|
115
|
+
isAutoScrollingRef.current = true;
|
116
|
+
listHandle.current?.scrollTo({ top: height });
|
117
|
+
requestAnimationFrame(() => {
|
118
|
+
isAutoScrollingRef.current = false;
|
119
|
+
});
|
120
|
+
}
|
121
|
+
});
|
122
|
+
},
|
123
|
+
[scrollRef, followOutput, live],
|
124
|
+
);
|
125
|
+
|
126
|
+
useEffect(() => {
|
127
|
+
// Force a re-render after initial mount
|
128
|
+
// This is here only because in VScode, for some reason,
|
129
|
+
// when this transcript is restored, the height isn't computed
|
130
|
+
// properly on the first render. This basically gives it a second
|
131
|
+
// change to compute the height and lay itself out.
|
132
|
+
const timer = setTimeout(() => {
|
133
|
+
forceUpdate();
|
134
|
+
}, 0);
|
135
|
+
return () => clearTimeout(timer);
|
136
|
+
}, []);
|
137
|
+
|
138
|
+
const [, forceRender] = useState({});
|
139
|
+
const forceUpdate = useCallback(() => forceRender({}), []);
|
140
|
+
|
141
|
+
const Footer = () => {
|
142
|
+
return showProgress ? (
|
143
|
+
<div className={clsx(styles.progressContainer)}>
|
144
|
+
<PulsingDots subtle={false} size="medium" />
|
145
|
+
</div>
|
146
|
+
) : undefined;
|
147
|
+
};
|
148
|
+
|
149
|
+
useEffect(() => {
|
150
|
+
// Listen to scroll events
|
151
|
+
const parent = scrollRef?.current;
|
152
|
+
if (parent) {
|
153
|
+
parent.addEventListener("scroll", handleScroll);
|
154
|
+
return () => parent.removeEventListener("scroll", handleScroll);
|
155
|
+
}
|
156
|
+
}, [scrollRef, handleScroll]);
|
157
|
+
|
158
|
+
return (
|
159
|
+
<Virtuoso
|
160
|
+
ref={listHandle}
|
161
|
+
customScrollParent={scrollRef?.current ? scrollRef.current : undefined}
|
162
|
+
style={{ height: "100%", width: "100%" }}
|
163
|
+
data={data}
|
164
|
+
defaultItemHeight={250}
|
165
|
+
itemContent={renderRow}
|
166
|
+
increaseViewportBy={{ top: 1000, bottom: 1000 }}
|
167
|
+
overscan={{ main: 2, reverse: 2 }}
|
168
|
+
className={clsx("transcript", className)}
|
169
|
+
isScrolling={isScrolling}
|
170
|
+
restoreStateFrom={getRestoreState()}
|
171
|
+
totalListHeightChanged={heightChanged}
|
172
|
+
components={{
|
173
|
+
Footer,
|
174
|
+
}}
|
175
|
+
/>
|
176
|
+
);
|
177
|
+
};
|
@@ -1,15 +1,15 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import markdownit from "markdown-it";
|
3
|
-
import
|
3
|
+
import { CSSProperties, forwardRef } from "react";
|
4
4
|
import "./MarkdownDiv.css";
|
5
5
|
|
6
6
|
interface MarkdownDivProps {
|
7
7
|
markdown: string;
|
8
|
-
style?:
|
8
|
+
style?: CSSProperties;
|
9
9
|
className?: string | string[];
|
10
10
|
}
|
11
11
|
|
12
|
-
export const MarkdownDiv =
|
12
|
+
export const MarkdownDiv = forwardRef<HTMLDivElement, MarkdownDivProps>(
|
13
13
|
({ markdown, style, className }, ref) => {
|
14
14
|
// Escape all tags
|
15
15
|
const escaped = markdown ? escape(markdown) : "";
|