inspect-ai 0.3.81__py3-none-any.whl → 0.3.83__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.
Files changed (297) hide show
  1. inspect_ai/__init__.py +2 -1
  2. inspect_ai/_cli/eval.py +35 -2
  3. inspect_ai/_cli/util.py +44 -1
  4. inspect_ai/_display/core/config.py +1 -1
  5. inspect_ai/_display/core/display.py +13 -4
  6. inspect_ai/_display/core/results.py +1 -1
  7. inspect_ai/_display/textual/app.py +14 -3
  8. inspect_ai/_display/textual/display.py +4 -0
  9. inspect_ai/_display/textual/widgets/samples.py +9 -3
  10. inspect_ai/_display/textual/widgets/task_detail.py +8 -8
  11. inspect_ai/_display/textual/widgets/tasks.py +17 -1
  12. inspect_ai/_display/textual/widgets/vscode.py +44 -0
  13. inspect_ai/_eval/eval.py +74 -25
  14. inspect_ai/_eval/evalset.py +22 -18
  15. inspect_ai/_eval/loader.py +34 -11
  16. inspect_ai/_eval/run.py +13 -15
  17. inspect_ai/_eval/score.py +13 -3
  18. inspect_ai/_eval/task/generate.py +8 -9
  19. inspect_ai/_eval/task/log.py +55 -6
  20. inspect_ai/_eval/task/run.py +51 -10
  21. inspect_ai/_eval/task/task.py +23 -9
  22. inspect_ai/_util/constants.py +2 -0
  23. inspect_ai/_util/file.py +30 -1
  24. inspect_ai/_util/json.py +37 -1
  25. inspect_ai/_util/registry.py +1 -0
  26. inspect_ai/_util/vscode.py +37 -0
  27. inspect_ai/_view/server.py +113 -1
  28. inspect_ai/_view/www/App.css +7 -1
  29. inspect_ai/_view/www/dist/assets/index.css +813 -415
  30. inspect_ai/_view/www/dist/assets/index.js +54475 -32003
  31. inspect_ai/_view/www/eslint.config.mjs +1 -1
  32. inspect_ai/_view/www/log-schema.json +137 -31
  33. inspect_ai/_view/www/node_modules/flatted/python/flatted.py +149 -0
  34. inspect_ai/_view/www/package.json +11 -2
  35. inspect_ai/_view/www/src/App.tsx +161 -853
  36. inspect_ai/_view/www/src/api/api-browser.ts +176 -5
  37. inspect_ai/_view/www/src/api/api-vscode.ts +75 -1
  38. inspect_ai/_view/www/src/api/client-api.ts +66 -10
  39. inspect_ai/_view/www/src/api/jsonrpc.ts +2 -0
  40. inspect_ai/_view/www/src/api/types.ts +107 -2
  41. inspect_ai/_view/www/src/appearance/icons.ts +2 -0
  42. inspect_ai/_view/www/src/components/AsciinemaPlayer.tsx +3 -3
  43. inspect_ai/_view/www/src/components/Card.tsx +6 -4
  44. inspect_ai/_view/www/src/components/DownloadPanel.tsx +2 -2
  45. inspect_ai/_view/www/src/components/ExpandablePanel.tsx +56 -61
  46. inspect_ai/_view/www/src/components/FindBand.tsx +17 -9
  47. inspect_ai/_view/www/src/components/HumanBaselineView.tsx +1 -1
  48. inspect_ai/_view/www/src/components/JsonPanel.tsx +14 -24
  49. inspect_ai/_view/www/src/components/LargeModal.tsx +2 -35
  50. inspect_ai/_view/www/src/components/LightboxCarousel.tsx +27 -11
  51. inspect_ai/_view/www/src/components/LinkButton.module.css +16 -0
  52. inspect_ai/_view/www/src/components/LinkButton.tsx +33 -0
  53. inspect_ai/_view/www/src/components/LiveVirtualList.module.css +11 -0
  54. inspect_ai/_view/www/src/components/LiveVirtualList.tsx +177 -0
  55. inspect_ai/_view/www/src/components/MarkdownDiv.tsx +116 -26
  56. inspect_ai/_view/www/src/components/MessageBand.tsx +14 -9
  57. inspect_ai/_view/www/src/components/Modal.module.css +38 -0
  58. inspect_ai/_view/www/src/components/Modal.tsx +77 -0
  59. inspect_ai/_view/www/src/components/MorePopOver.tsx +3 -3
  60. inspect_ai/_view/www/src/components/NavPills.tsx +20 -8
  61. inspect_ai/_view/www/src/components/NoContentsPanel.module.css +12 -0
  62. inspect_ai/_view/www/src/components/NoContentsPanel.tsx +20 -0
  63. inspect_ai/_view/www/src/components/ProgressBar.module.css +5 -4
  64. inspect_ai/_view/www/src/components/ProgressBar.tsx +3 -2
  65. inspect_ai/_view/www/src/components/PulsingDots.module.css +81 -0
  66. inspect_ai/_view/www/src/components/PulsingDots.tsx +45 -0
  67. inspect_ai/_view/www/src/components/TabSet.tsx +4 -37
  68. inspect_ai/_view/www/src/components/ToolButton.tsx +3 -4
  69. inspect_ai/_view/www/src/index.tsx +26 -94
  70. inspect_ai/_view/www/src/logfile/remoteLogFile.ts +9 -1
  71. inspect_ai/_view/www/src/logfile/remoteZipFile.ts +30 -4
  72. inspect_ai/_view/www/src/metadata/RenderedContent.tsx +4 -6
  73. inspect_ai/_view/www/src/plan/DetailStep.module.css +4 -0
  74. inspect_ai/_view/www/src/plan/DetailStep.tsx +6 -3
  75. inspect_ai/_view/www/src/plan/ScorerDetailView.tsx +1 -1
  76. inspect_ai/_view/www/src/plan/SolverDetailView.module.css +2 -1
  77. inspect_ai/_view/www/src/samples/InlineSampleDisplay.module.css +9 -1
  78. inspect_ai/_view/www/src/samples/InlineSampleDisplay.tsx +74 -28
  79. inspect_ai/_view/www/src/samples/SampleDialog.tsx +58 -22
  80. inspect_ai/_view/www/src/samples/SampleDisplay.module.css +4 -0
  81. inspect_ai/_view/www/src/samples/SampleDisplay.tsx +135 -104
  82. inspect_ai/_view/www/src/samples/SampleSummaryView.module.css +10 -0
  83. inspect_ai/_view/www/src/samples/SampleSummaryView.tsx +83 -36
  84. inspect_ai/_view/www/src/samples/SamplesTools.tsx +35 -30
  85. inspect_ai/_view/www/src/samples/chat/ChatMessage.tsx +2 -1
  86. inspect_ai/_view/www/src/samples/chat/ChatMessageRenderer.tsx +1 -1
  87. inspect_ai/_view/www/src/samples/chat/ChatViewVirtualList.tsx +45 -53
  88. inspect_ai/_view/www/src/samples/chat/MessageContent.tsx +6 -1
  89. inspect_ai/_view/www/src/samples/chat/MessageContents.tsx +5 -0
  90. inspect_ai/_view/www/src/samples/chat/messages.ts +36 -0
  91. inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.module.css +3 -0
  92. inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.tsx +11 -1
  93. inspect_ai/_view/www/src/samples/chat/tools/ToolInput.tsx +22 -46
  94. inspect_ai/_view/www/src/samples/descriptor/samplesDescriptor.tsx +34 -20
  95. inspect_ai/_view/www/src/samples/descriptor/score/BooleanScoreDescriptor.module.css +3 -3
  96. inspect_ai/_view/www/src/samples/descriptor/score/BooleanScoreDescriptor.tsx +1 -1
  97. inspect_ai/_view/www/src/samples/descriptor/score/ObjectScoreDescriptor.module.css +4 -4
  98. inspect_ai/_view/www/src/samples/descriptor/score/ObjectScoreDescriptor.tsx +10 -10
  99. inspect_ai/_view/www/src/samples/descriptor/types.ts +6 -5
  100. inspect_ai/_view/www/src/samples/list/SampleFooter.module.css +22 -3
  101. inspect_ai/_view/www/src/samples/list/SampleFooter.tsx +27 -2
  102. inspect_ai/_view/www/src/samples/list/SampleList.tsx +122 -85
  103. inspect_ai/_view/www/src/samples/list/SampleRow.module.css +6 -0
  104. inspect_ai/_view/www/src/samples/list/SampleRow.tsx +28 -15
  105. inspect_ai/_view/www/src/samples/sample-tools/SelectScorer.tsx +29 -18
  106. inspect_ai/_view/www/src/samples/sample-tools/SortFilter.tsx +28 -28
  107. inspect_ai/_view/www/src/samples/sample-tools/sample-filter/SampleFilter.tsx +19 -9
  108. inspect_ai/_view/www/src/samples/sampleDataAdapter.ts +33 -0
  109. inspect_ai/_view/www/src/samples/sampleLimit.ts +2 -2
  110. inspect_ai/_view/www/src/samples/scores/SampleScores.tsx +12 -27
  111. inspect_ai/_view/www/src/samples/scores/SampleScoresGrid.module.css +38 -0
  112. inspect_ai/_view/www/src/samples/scores/SampleScoresGrid.tsx +118 -0
  113. inspect_ai/_view/www/src/samples/scores/{SampleScoreView.module.css → SampleScoresView.module.css} +10 -1
  114. inspect_ai/_view/www/src/samples/scores/SampleScoresView.tsx +78 -0
  115. inspect_ai/_view/www/src/samples/transcript/ErrorEventView.tsx +0 -13
  116. inspect_ai/_view/www/src/samples/transcript/InfoEventView.tsx +0 -13
  117. inspect_ai/_view/www/src/samples/transcript/InputEventView.tsx +0 -13
  118. inspect_ai/_view/www/src/samples/transcript/ModelEventView.module.css +4 -0
  119. inspect_ai/_view/www/src/samples/transcript/ModelEventView.tsx +10 -24
  120. inspect_ai/_view/www/src/samples/transcript/SampleInitEventView.tsx +0 -13
  121. inspect_ai/_view/www/src/samples/transcript/SampleLimitEventView.tsx +4 -22
  122. inspect_ai/_view/www/src/samples/transcript/SandboxEventView.tsx +15 -24
  123. inspect_ai/_view/www/src/samples/transcript/ScoreEventView.tsx +0 -13
  124. inspect_ai/_view/www/src/samples/transcript/StepEventView.tsx +6 -28
  125. inspect_ai/_view/www/src/samples/transcript/SubtaskEventView.tsx +24 -34
  126. inspect_ai/_view/www/src/samples/transcript/ToolEventView.module.css +4 -0
  127. inspect_ai/_view/www/src/samples/transcript/ToolEventView.tsx +33 -17
  128. inspect_ai/_view/www/src/samples/transcript/TranscriptView.tsx +197 -338
  129. inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.module.css +16 -0
  130. inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.tsx +44 -0
  131. inspect_ai/_view/www/src/samples/transcript/event/EventNav.tsx +7 -4
  132. inspect_ai/_view/www/src/samples/transcript/event/EventPanel.tsx +81 -60
  133. inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.module.css +23 -0
  134. inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.tsx +27 -0
  135. inspect_ai/_view/www/src/samples/transcript/state/StateEventRenderers.tsx +29 -1
  136. inspect_ai/_view/www/src/samples/transcript/state/StateEventView.tsx +102 -72
  137. inspect_ai/_view/www/src/scoring/utils.ts +87 -0
  138. inspect_ai/_view/www/src/state/appSlice.ts +244 -0
  139. inspect_ai/_view/www/src/state/hooks.ts +399 -0
  140. inspect_ai/_view/www/src/state/logPolling.ts +200 -0
  141. inspect_ai/_view/www/src/state/logSlice.ts +224 -0
  142. inspect_ai/_view/www/src/state/logsPolling.ts +118 -0
  143. inspect_ai/_view/www/src/state/logsSlice.ts +181 -0
  144. inspect_ai/_view/www/src/state/samplePolling.ts +314 -0
  145. inspect_ai/_view/www/src/state/sampleSlice.ts +140 -0
  146. inspect_ai/_view/www/src/state/sampleUtils.ts +21 -0
  147. inspect_ai/_view/www/src/state/scrolling.ts +206 -0
  148. inspect_ai/_view/www/src/state/store.ts +168 -0
  149. inspect_ai/_view/www/src/state/store_filter.ts +84 -0
  150. inspect_ai/_view/www/src/state/utils.ts +23 -0
  151. inspect_ai/_view/www/src/storage/index.ts +26 -0
  152. inspect_ai/_view/www/src/types/log.d.ts +36 -26
  153. inspect_ai/_view/www/src/types/markdown-it-katex.d.ts +21 -0
  154. inspect_ai/_view/www/src/types.ts +94 -32
  155. inspect_ai/_view/www/src/utils/attachments.ts +58 -23
  156. inspect_ai/_view/www/src/utils/json-worker.ts +79 -12
  157. inspect_ai/_view/www/src/utils/logger.ts +52 -0
  158. inspect_ai/_view/www/src/utils/polling.ts +100 -0
  159. inspect_ai/_view/www/src/utils/react.ts +30 -0
  160. inspect_ai/_view/www/src/utils/vscode.ts +1 -1
  161. inspect_ai/_view/www/src/workspace/WorkSpace.tsx +184 -217
  162. inspect_ai/_view/www/src/workspace/WorkSpaceView.tsx +11 -53
  163. inspect_ai/_view/www/src/workspace/navbar/Navbar.tsx +8 -18
  164. inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.module.css +1 -0
  165. inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.tsx +40 -22
  166. inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.module.css +16 -1
  167. inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.tsx +159 -103
  168. inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.module.css +32 -0
  169. inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.tsx +32 -0
  170. inspect_ai/_view/www/src/workspace/navbar/ScoreGrid.module.css +35 -0
  171. inspect_ai/_view/www/src/workspace/navbar/ScoreGrid.tsx +117 -0
  172. inspect_ai/_view/www/src/workspace/navbar/SecondaryBar.tsx +12 -14
  173. inspect_ai/_view/www/src/workspace/navbar/StatusPanel.tsx +6 -2
  174. inspect_ai/_view/www/src/workspace/sidebar/LogDirectoryTitleView.tsx +4 -4
  175. inspect_ai/_view/www/src/workspace/sidebar/Sidebar.module.css +3 -2
  176. inspect_ai/_view/www/src/workspace/sidebar/Sidebar.tsx +28 -13
  177. inspect_ai/_view/www/src/workspace/tabs/InfoTab.tsx +5 -10
  178. inspect_ai/_view/www/src/workspace/tabs/JsonTab.tsx +4 -4
  179. inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.module.css +22 -0
  180. inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.tsx +19 -0
  181. inspect_ai/_view/www/src/workspace/tabs/SamplesTab.tsx +128 -115
  182. inspect_ai/_view/www/src/workspace/tabs/grouping.ts +37 -5
  183. inspect_ai/_view/www/src/workspace/tabs/types.ts +4 -0
  184. inspect_ai/_view/www/src/workspace/types.ts +4 -3
  185. inspect_ai/_view/www/src/workspace/utils.ts +4 -4
  186. inspect_ai/_view/www/vite.config.js +6 -0
  187. inspect_ai/_view/www/yarn.lock +464 -355
  188. inspect_ai/agent/__init__.py +36 -0
  189. inspect_ai/agent/_agent.py +268 -0
  190. inspect_ai/agent/_as_solver.py +72 -0
  191. inspect_ai/agent/_as_tool.py +122 -0
  192. inspect_ai/{solver → agent}/_bridge/bridge.py +23 -37
  193. inspect_ai/{solver → agent}/_bridge/patch.py +9 -8
  194. inspect_ai/agent/_filter.py +46 -0
  195. inspect_ai/agent/_handoff.py +93 -0
  196. inspect_ai/{solver/_human_agent → agent/_human}/agent.py +11 -12
  197. inspect_ai/{solver/_human_agent → agent/_human}/commands/__init__.py +2 -3
  198. inspect_ai/{solver/_human_agent → agent/_human}/commands/clock.py +3 -1
  199. inspect_ai/{solver/_human_agent → agent/_human}/commands/score.py +5 -5
  200. inspect_ai/{solver/_human_agent → agent/_human}/install.py +6 -3
  201. inspect_ai/{solver/_human_agent → agent/_human}/service.py +7 -3
  202. inspect_ai/{solver/_human_agent → agent/_human}/state.py +5 -5
  203. inspect_ai/agent/_react.py +241 -0
  204. inspect_ai/agent/_run.py +36 -0
  205. inspect_ai/agent/_types.py +81 -0
  206. inspect_ai/log/_condense.py +26 -0
  207. inspect_ai/log/_log.py +17 -5
  208. inspect_ai/log/_recorders/buffer/__init__.py +14 -0
  209. inspect_ai/log/_recorders/buffer/buffer.py +30 -0
  210. inspect_ai/log/_recorders/buffer/database.py +685 -0
  211. inspect_ai/log/_recorders/buffer/filestore.py +259 -0
  212. inspect_ai/log/_recorders/buffer/types.py +84 -0
  213. inspect_ai/log/_recorders/eval.py +2 -11
  214. inspect_ai/log/_recorders/types.py +30 -0
  215. inspect_ai/log/_transcript.py +32 -2
  216. inspect_ai/model/__init__.py +7 -1
  217. inspect_ai/model/_call_tools.py +257 -52
  218. inspect_ai/model/_chat_message.py +7 -4
  219. inspect_ai/model/_conversation.py +13 -62
  220. inspect_ai/model/_display.py +85 -0
  221. inspect_ai/model/_generate_config.py +2 -2
  222. inspect_ai/model/_model.py +114 -14
  223. inspect_ai/model/_model_output.py +14 -9
  224. inspect_ai/model/_openai.py +16 -4
  225. inspect_ai/model/_openai_computer_use.py +162 -0
  226. inspect_ai/model/_openai_responses.py +319 -165
  227. inspect_ai/model/_providers/anthropic.py +20 -21
  228. inspect_ai/model/_providers/azureai.py +24 -13
  229. inspect_ai/model/_providers/bedrock.py +1 -7
  230. inspect_ai/model/_providers/cloudflare.py +3 -3
  231. inspect_ai/model/_providers/goodfire.py +2 -6
  232. inspect_ai/model/_providers/google.py +11 -10
  233. inspect_ai/model/_providers/groq.py +6 -3
  234. inspect_ai/model/_providers/hf.py +7 -3
  235. inspect_ai/model/_providers/mistral.py +7 -10
  236. inspect_ai/model/_providers/openai.py +47 -17
  237. inspect_ai/model/_providers/openai_o1.py +11 -4
  238. inspect_ai/model/_providers/openai_responses.py +12 -14
  239. inspect_ai/model/_providers/providers.py +2 -2
  240. inspect_ai/model/_providers/together.py +12 -2
  241. inspect_ai/model/_providers/util/chatapi.py +7 -2
  242. inspect_ai/model/_providers/util/hf_handler.py +4 -2
  243. inspect_ai/model/_providers/util/llama31.py +4 -2
  244. inspect_ai/model/_providers/vertex.py +11 -9
  245. inspect_ai/model/_providers/vllm.py +4 -4
  246. inspect_ai/scorer/__init__.py +2 -0
  247. inspect_ai/scorer/_metrics/__init__.py +2 -0
  248. inspect_ai/scorer/_metrics/grouped.py +84 -0
  249. inspect_ai/scorer/_score.py +26 -6
  250. inspect_ai/solver/__init__.py +2 -2
  251. inspect_ai/solver/_basic_agent.py +22 -9
  252. inspect_ai/solver/_bridge.py +31 -0
  253. inspect_ai/solver/_chain.py +20 -12
  254. inspect_ai/solver/_fork.py +5 -1
  255. inspect_ai/solver/_human_agent.py +52 -0
  256. inspect_ai/solver/_prompt.py +3 -1
  257. inspect_ai/solver/_run.py +59 -0
  258. inspect_ai/solver/_solver.py +14 -4
  259. inspect_ai/solver/_task_state.py +5 -3
  260. inspect_ai/tool/_tool_call.py +15 -8
  261. inspect_ai/tool/_tool_def.py +17 -12
  262. inspect_ai/tool/_tool_support_helpers.py +4 -4
  263. inspect_ai/tool/_tool_with.py +14 -11
  264. inspect_ai/tool/_tools/_bash_session.py +11 -2
  265. inspect_ai/tool/_tools/_computer/_common.py +18 -2
  266. inspect_ai/tool/_tools/_computer/_computer.py +18 -2
  267. inspect_ai/tool/_tools/_computer/_resources/tool/_constants.py +2 -0
  268. inspect_ai/tool/_tools/_computer/_resources/tool/_x11_client.py +17 -0
  269. inspect_ai/tool/_tools/_think.py +1 -1
  270. inspect_ai/tool/_tools/_web_browser/_web_browser.py +103 -62
  271. inspect_ai/util/__init__.py +2 -0
  272. inspect_ai/util/_anyio.py +27 -0
  273. inspect_ai/util/_sandbox/__init__.py +2 -1
  274. inspect_ai/util/_sandbox/context.py +32 -7
  275. inspect_ai/util/_sandbox/docker/cleanup.py +4 -0
  276. inspect_ai/util/_sandbox/docker/compose.py +2 -2
  277. inspect_ai/util/_sandbox/docker/docker.py +12 -1
  278. inspect_ai/util/_store_model.py +30 -7
  279. inspect_ai/util/_subprocess.py +13 -3
  280. inspect_ai/util/_subtask.py +1 -0
  281. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.dist-info}/METADATA +1 -1
  282. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.dist-info}/RECORD +295 -229
  283. inspect_ai/_view/www/src/samples/scores/SampleScoreView.tsx +0 -169
  284. inspect_ai/_view/www/src/samples/transcript/SampleTranscript.tsx +0 -22
  285. /inspect_ai/{solver → agent}/_bridge/__init__.py +0 -0
  286. /inspect_ai/{solver/_human_agent → agent/_human}/__init__.py +0 -0
  287. /inspect_ai/{solver/_human_agent → agent/_human}/commands/command.py +0 -0
  288. /inspect_ai/{solver/_human_agent → agent/_human}/commands/instructions.py +0 -0
  289. /inspect_ai/{solver/_human_agent → agent/_human}/commands/note.py +0 -0
  290. /inspect_ai/{solver/_human_agent → agent/_human}/commands/status.py +0 -0
  291. /inspect_ai/{solver/_human_agent → agent/_human}/commands/submit.py +0 -0
  292. /inspect_ai/{solver/_human_agent → agent/_human}/panel.py +0 -0
  293. /inspect_ai/{solver/_human_agent → agent/_human}/view.py +0 -0
  294. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.dist-info}/WHEEL +0 -0
  295. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.dist-info}/entry_points.txt +0 -0
  296. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.dist-info}/licenses/LICENSE +0 -0
  297. {inspect_ai-0.3.81.dist-info → inspect_ai-0.3.83.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
- border,
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
- useEffect(() => {
35
- setIsCollapsed(collapse);
36
- }, [collapse]);
29
+ const [showToggle, setShowToggle] = useState(false);
30
+ const lineHeightRef = useRef<number>(0);
37
31
 
38
- const checkOverflow = useCallback(
39
- (entry: ResizeObserverEntry) => {
40
- const element = entry.target as HTMLDivElement;
32
+ const checkOverflow = useCallback(
33
+ (entry: ResizeObserverEntry) => {
34
+ const element = entry.target as HTMLDivElement;
41
35
 
42
- // Calculate line height if we haven't yet
43
- if (!lineHeightRef.current) {
44
- const computedStyle = window.getComputedStyle(element);
45
- lineHeightRef.current = parseInt(computedStyle.lineHeight) || 16; // fallback to 16px if can't get line height
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
- const maxCollapsedHeight = lines * lineHeightRef.current;
49
- const contentHeight = element.scrollHeight;
42
+ const maxCollapsedHeight = lines * lineHeightRef.current;
43
+ const contentHeight = element.scrollHeight;
50
44
 
51
- setShowToggle(contentHeight > maxCollapsedHeight);
52
- },
53
- [lines],
54
- );
45
+ setShowToggle(contentHeight > maxCollapsedHeight);
46
+ },
47
+ [lines],
48
+ );
49
+ const contentRef = useResizeObserver(checkOverflow);
55
50
 
56
- const contentRef = useResizeObserver(checkOverflow);
51
+ const baseStyles = {
52
+ overflow: "hidden",
53
+ ...(collapsed && {
54
+ maxHeight: `${lines}em`,
55
+ }),
56
+ };
57
57
 
58
- const baseStyles = {
59
- overflow: "hidden",
60
- ...(isCollapsed && {
61
- maxHeight: `${lines}em`,
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
- return (
66
- <div className={clsx(className)}>
67
- <div
68
- style={baseStyles}
69
- ref={contentRef}
70
- className={clsx(
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
- {showToggle && (
80
- <MoreToggle
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> = ({ hideBand }) => {
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
- hideBand();
87
+ storeHideFind();
88
88
  } else if (e.key === "Enter") {
89
89
  handleSearch(false);
90
90
  }
91
91
  },
92
- [hideBand, handleSearch],
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={() => handleSearch(true)}
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={() => handleSearch(false)}
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={hideBand}
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 { highlightElement } from "prismjs";
3
- import React, { useEffect, useMemo, useRef } from "react";
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?: React.CSSProperties;
11
+ style?: CSSProperties;
14
12
  className?: string | string[];
15
13
  }
16
14
 
17
- export const JSONPanel: React.FC<JSONPanelProps> = ({
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
- <pre
38
- className={clsx("json-panel", simple ? "simple" : "", className)}
39
- style={style}
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
- {sourceCode}
47
- </code>
48
- </pre>
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} onScroll={onScroll}>
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, useState } from "react";
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] = useState(false);
20
- const [showOverlay, setShowOverlay] = useState(false);
21
- const [currentIndex, setCurrentIndex] = useState(0);
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
- [setCurrentIndex, setShowOverlay],
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((prev) => {
50
- return (prev + 1) % slides.length;
51
- });
59
+ setCurrentIndex(currentIndex + 1);
52
60
  }, [slides, setCurrentIndex]);
53
61
 
54
62
  const showPrev = useCallback(() => {
55
- setCurrentIndex((prev) => (prev - 1 + slides.length) % slides.length);
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={() => openLightbox(index)}
100
+ onClick={handleThumbClick}
85
101
  >
86
102
  <div>{slide.label}</div>
87
103
  <div>
@@ -0,0 +1,16 @@
1
+ .button {
2
+ display: flex;
3
+ border: none;
4
+ flex-direction: row;
5
+ background-color: unset;
6
+ color: var(--bs-link-color);
7
+ }
8
+
9
+ .button:hover {
10
+ color: var(--bs-link-hover-color);
11
+ cursor: pointer;
12
+ }
13
+
14
+ .label {
15
+ margin-left: 0.4em;
16
+ }
@@ -0,0 +1,33 @@
1
+ import clsx from "clsx";
2
+ import { FC } from "react";
3
+ import styles from "./LinkButton.module.css";
4
+
5
+ interface LinkButtonProps {
6
+ id?: string;
7
+ text?: string;
8
+ icon?: string;
9
+ onClick: () => void;
10
+ className?: string | string[];
11
+ }
12
+
13
+ /**
14
+ * LightboxCarousel component provides a carousel with lightbox functionality.
15
+ */
16
+ export const LinkButton: FC<LinkButtonProps> = ({
17
+ id,
18
+ text,
19
+ icon,
20
+ className,
21
+ onClick,
22
+ }) => {
23
+ return (
24
+ <button
25
+ id={id}
26
+ onClick={onClick}
27
+ className={clsx(className, styles.button, "text-size-smaller")}
28
+ >
29
+ {icon ? <i className={clsx(icon)}></i> : undefined}
30
+ {text ? <div className={clsx(styles.label)}>{text}</div> : undefined}
31
+ </button>
32
+ );
33
+ };
@@ -0,0 +1,11 @@
1
+ .progressContainer {
2
+ width: 100%;
3
+ display: flex;
4
+ align-content: flex-start;
5
+ justify-content: flex-start;
6
+ margin-left: 2.5em;
7
+ }
8
+
9
+ .progressText {
10
+ margin-left: 0.4em;
11
+ }