From e2c0a414a2841bfe076dddfb8c79b0b0053c5357 Mon Sep 17 00:00:00 2001 From: Charles Teague Date: Wed, 26 Feb 2025 14:16:22 -0500 Subject: [PATCH] Fix React Lint (#1414) * Add react linting * Fix react linting * additional lint cleanup * Fix no-undef lint * Fix additional dependency lints --- src/inspect_ai/_view/www/dist/assets/index.js | 170 ++++++------ src/inspect_ai/_view/www/eslint.config.mjs | 25 +- src/inspect_ai/_view/www/package.json | 6 +- src/inspect_ai/_view/www/src/App.tsx | 4 +- .../_view/www/src/components/AnsiDisplay.tsx | 7 +- .../_view/www/src/components/Card.tsx | 17 +- .../www/src/components/DownloadButton.tsx | 3 +- .../_view/www/src/components/EmptyPanel.tsx | 4 +- .../_view/www/src/components/ErrorPanel.tsx | 3 +- .../www/src/components/ExpandablePanel.tsx | 18 +- .../_view/www/src/components/FindBand.tsx | 6 +- .../www/src/components/HumanBaselineView.tsx | 6 +- .../_view/www/src/components/LabeledValue.tsx | 9 +- .../_view/www/src/components/LargeModal.tsx | 31 ++- .../www/src/components/LightboxCarousel.tsx | 8 +- .../_view/www/src/components/MessageBand.tsx | 3 +- .../_view/www/src/components/NavPills.tsx | 17 +- .../_view/www/src/components/ProgressBar.tsx | 3 +- .../_view/www/src/components/TabSet.tsx | 36 +-- src/inspect_ai/_view/www/src/index.tsx | 4 +- .../_view/www/src/metadata/MetaDataGrid.tsx | 6 +- .../_view/www/src/metadata/MetaDataView.tsx | 5 +- .../_view/www/src/plan/DatasetDetailView.tsx | 5 +- .../_view/www/src/plan/DetailStep.tsx | 3 +- .../_view/www/src/plan/PlanCard.tsx | 7 +- .../_view/www/src/plan/PlanDetailView.tsx | 15 +- .../_view/www/src/plan/ScorerDetailView.tsx | 3 +- .../_view/www/src/plan/SolverDetailView.tsx | 6 +- .../www/src/samples/InlineSampleDisplay.tsx | 4 +- .../_view/www/src/samples/SampleDialog.tsx | 6 +- .../_view/www/src/samples/SampleDisplay.tsx | 4 +- .../www/src/samples/SampleSummaryView.tsx | 4 +- .../_view/www/src/samples/SamplesTools.tsx | 3 +- .../www/src/samples/chat/ChatMessage.tsx | 3 +- .../src/samples/chat/ChatMessageRenderer.tsx | 3 +- .../www/src/samples/chat/ChatMessageRow.tsx | 3 +- .../_view/www/src/samples/chat/ChatView.tsx | 3 +- .../src/samples/chat/ChatViewVirtualList.tsx | 4 +- .../www/src/samples/chat/MessageContent.tsx | 10 +- .../www/src/samples/chat/MessageContents.tsx | 4 +- .../src/samples/chat/tools/ToolCallView.tsx | 4 +- .../www/src/samples/chat/tools/ToolInput.tsx | 4 +- .../www/src/samples/chat/tools/ToolOutput.tsx | 5 +- .../www/src/samples/chat/tools/ToolTitle.tsx | 4 +- .../src/samples/error/FlatSampleErrorView.tsx | 5 +- .../www/src/samples/error/SampleErrorView.tsx | 5 +- .../www/src/samples/list/SampleFooter.tsx | 3 +- .../www/src/samples/list/SampleHeader.tsx | 3 +- .../_view/www/src/samples/list/SampleList.tsx | 58 +++-- .../_view/www/src/samples/list/SampleRow.tsx | 3 +- .../www/src/samples/list/SampleSeparator.tsx | 3 +- .../src/samples/sample-tools/EpochFilter.tsx | 4 +- .../src/samples/sample-tools/SelectScorer.tsx | 7 +- .../src/samples/sample-tools/SortFilter.tsx | 7 +- .../sample-filter/SampleFilter.tsx | 4 +- .../src/samples/scores/SampleScoreView.tsx | 3 +- .../www/src/samples/scores/SampleScores.tsx | 4 +- .../samples/transcript/ApprovalEventView.tsx | 3 +- .../src/samples/transcript/ErrorEventView.tsx | 3 +- .../src/samples/transcript/InfoEventView.tsx | 3 +- .../src/samples/transcript/InputEventView.tsx | 3 +- .../samples/transcript/LoggerEventView.tsx | 3 +- .../src/samples/transcript/ModelEventView.tsx | 20 +- .../transcript/SampleInitEventView.tsx | 3 +- .../transcript/SampleLimitEventView.tsx | 9 +- .../samples/transcript/SampleTranscript.tsx | 4 +- .../samples/transcript/SandboxEventView.tsx | 11 +- .../src/samples/transcript/ScoreEventView.tsx | 4 +- .../src/samples/transcript/StepEventView.tsx | 6 +- .../samples/transcript/SubtaskEventView.tsx | 16 +- .../src/samples/transcript/ToolEventView.tsx | 4 +- .../src/samples/transcript/TranscriptView.tsx | 23 +- .../src/samples/transcript/event/EventNav.tsx | 3 +- .../samples/transcript/event/EventNavs.tsx | 3 +- .../src/samples/transcript/event/EventRow.tsx | 5 +- .../samples/transcript/event/EventSection.tsx | 4 +- .../transcript/state/StateDiffView.tsx | 3 +- .../transcript/state/StateEventRenderers.tsx | 6 +- .../transcript/state/StateEventView.tsx | 4 +- src/inspect_ai/_view/www/src/types/log.d.ts | 1 - .../_view/www/src/usage/ModelTokenTable.tsx | 5 +- .../_view/www/src/usage/ModelUsagePanel.tsx | 4 +- .../_view/www/src/usage/TokenTable.tsx | 10 +- .../_view/www/src/usage/UsageCard.tsx | 3 +- .../_view/www/src/workspace/WorkSpace.tsx | 11 +- .../_view/www/src/workspace/WorkSpaceView.tsx | 11 +- .../src/workspace/error/TaskErrorPanel.tsx | 3 +- .../_view/www/src/workspace/navbar/Navbar.tsx | 3 +- .../www/src/workspace/navbar/PrimaryBar.tsx | 6 +- .../www/src/workspace/navbar/ResultsPanel.tsx | 7 +- .../www/src/workspace/navbar/SecondaryBar.tsx | 9 +- .../www/src/workspace/navbar/StatusPanel.tsx | 13 +- .../www/src/workspace/sidebar/EvalStatus.tsx | 9 +- .../sidebar/LogDirectoryTitleView.tsx | 3 +- .../www/src/workspace/sidebar/Sidebar.tsx | 3 +- .../src/workspace/sidebar/SidebarLogEntry.tsx | 4 +- .../workspace/sidebar/SidebarScoreView.tsx | 3 +- .../workspace/sidebar/SidebarScoresView.tsx | 4 +- .../_view/www/src/workspace/tabs/InfoTab.tsx | 4 +- .../_view/www/src/workspace/tabs/JsonTab.tsx | 7 +- .../www/src/workspace/tabs/SamplesTab.tsx | 13 +- src/inspect_ai/_view/www/yarn.lock | 241 +++++++++++++++++- 102 files changed, 707 insertions(+), 420 deletions(-) diff --git a/src/inspect_ai/_view/www/dist/assets/index.js b/src/inspect_ai/_view/www/dist/assets/index.js index f8fe1de8f..6d10ca759 100644 --- a/src/inspect_ai/_view/www/dist/assets/index.js +++ b/src/inspect_ai/_view/www/dist/assets/index.js @@ -15897,10 +15897,12 @@ var require_assets = __commonJS({ pill }; const NavPills = ({ children: children2 }) => { - if (!(children2 == null ? void 0 : children2.length)) { - return null; + const [activeItem, setActiveItem] = reactExports.useState( + children2 ? children2[0].props["title"] : null + ); + if (!activeItem || !children2) { + return void 0; } - const [activeItem, setActiveItem] = reactExports.useState(children2[0].props["title"]); const navPills = children2.map((nav2, idx) => { var _a2; const title2 = typeof nav2 === "object" ? ((_a2 = nav2["props"]) == null ? void 0 : _a2.title) || `Tab ${idx}` : `Tab ${idx}`; @@ -25406,11 +25408,7 @@ categories: ${categories.join(" ")}`; flex: flex$1, label: label$5 }; - const SortFilter = ({ - sort, - setSort, - epochs - }) => { + const SortFilter = ({ sort, setSort, epochs }) => { const options2 = [ { label: "sample asc", val: kSampleAscVal }, { label: "sample desc", val: kSampleDescVal } @@ -49264,11 +49262,7 @@ self.onmessage = function (e) { jsonTab }; const kJsonMaxSize = 1e7; - const JsonTab = ({ - logFile, - capabilities: capabilities2, - json - }) => { + const JsonTab = ({ logFile, capabilities: capabilities2, json }) => { if (logFile && json.length > kJsonMaxSize && capabilities2.downloadFiles) { const file = `${filename(logFile)}.json`; return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$K.jsonTab, children: /* @__PURE__ */ jsxRuntimeExports.jsx( @@ -49381,7 +49375,8 @@ self.onmessage = function (e) { children: children2 }) => { const tabContentsId = computeTabContentsId(id); - const tabContentsRef = scrollRef || reactExports.useRef(null); + const panelRef = reactExports.useRef(null); + const tabContentsRef = scrollRef || panelRef; reactExports.useEffect(() => { if (!selected2 || scrollPosition === void 0 || !tabContentsRef.current) return; @@ -49811,10 +49806,7 @@ self.onmessage = function (e) { tableH, model }; - const TokenTable = ({ - className: className2, - children: children2 - }) => { + const TokenTable = ({ className: className2, children: children2 }) => { return /* @__PURE__ */ jsxRuntimeExports.jsx( "table", { @@ -53037,9 +53029,7 @@ self.onmessage = function (e) { } return "Error"; }; - const FlatSampleError = ({ - message: message2 - }) => { + const FlatSampleError = ({ message: message2 }) => { return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx(styles$C.flatBody), children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: clsx(ApplicationIcons.error, styles$C.iconSmall) }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$C.lineBase), children: errorType(message2) }) @@ -53758,9 +53748,6 @@ self.onmessage = function (e) { ] }); }; const APICodeCell = ({ id, contents: contents2 }) => { - if (!contents2) { - return null; - } const codeRef = reactExports.useRef(null); const sourceCode = reactExports.useMemo(() => { return JSON.stringify(contents2, void 0, 2); @@ -53769,7 +53756,10 @@ self.onmessage = function (e) { if (codeRef.current) { prismExports.highlightElement(codeRef.current); } - }, [codeRef.current, contents2]); + }, [contents2]); + if (!contents2) { + return null; + } return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: styles$t.codePre, children: /* @__PURE__ */ jsxRuntimeExports.jsx( "code", { @@ -60337,9 +60327,7 @@ ${events} next, prev }; - const LightboxCarousel = ({ - slides - }) => { + const LightboxCarousel = ({ slides }) => { const [isOpen, setIsOpen] = reactExports.useState(false); const [showOverlay, setShowOverlay] = reactExports.useState(false); const [currentIndex, setCurrentIndex] = reactExports.useState(0); @@ -60990,7 +60978,7 @@ ${events} (state) => { setTranscriptState({ ...state }); }, - [transcriptState, setTranscriptState] + [setTranscriptState] ); return /* @__PURE__ */ jsxRuntimeExports.jsx( EventPanel, @@ -61183,14 +61171,14 @@ ${events} ); }; const SubtaskSummary = ({ input: input2, result: result2 }) => { - result2 = typeof result2 === "object" ? result2 : { result: result2 }; + const output2 = typeof result2 === "object" ? result2 : { result: result2 }; return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx(styles$n.subtaskSummary), children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-style-label"), children: "Input" }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-size-large", styles$n.subtaskLabel) }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-style-label"), children: "Output" }), - /* @__PURE__ */ jsxRuntimeExports.jsx(Rendered, { values: input2 }), + input2 ? /* @__PURE__ */ jsxRuntimeExports.jsx(Rendered, { values: input2 }) : void 0, /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-size-title-secondary", styles$n.subtaskLabel), children: /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: ApplicationIcons.arrows.right }) }), - /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Rendered, { values: result2 }) }) + /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Rendered, { values: output2 }) }) ] }); }; const Rendered = ({ values }) => { @@ -61446,7 +61434,7 @@ ${events} (state) => { setTranscriptState(state); }, - [transcriptState, setTranscriptState] + [setTranscriptState] ); return /* @__PURE__ */ jsxRuntimeExports.jsx( TranscriptVirtualListComponent, @@ -61464,7 +61452,7 @@ ${events} (eventId, state) => { setTranscriptState({ ...transcriptState, [eventId]: state }); }, - [setTranscriptState] + [transcriptState, setTranscriptState] ); const [followOutput, setFollowOutput] = reactExports.useState(false); const renderRow = (item2, index2) => { @@ -61512,6 +61500,12 @@ ${events} setTranscriptState, eventNodes }) => { + const setEventState = reactExports.useCallback( + (state, eventId) => { + setTranscriptState({ ...transcriptState, [eventId]: state }); + }, + [setTranscriptState, transcriptState] + ); const rows = eventNodes.map((eventNode2, index2) => { const clz = [styles$k.eventNode]; if (eventNode2.depth % 2 == 0) { @@ -61521,12 +61515,6 @@ ${events} clz.push(styles$k.lastNode); } const eventId = `${id}-event${index2}`; - const setEventState = reactExports.useCallback( - (state) => { - setTranscriptState({ ...transcriptState, [eventId]: state }); - }, - [setTranscriptState, transcriptState] - ); const row2 = /* @__PURE__ */ jsxRuntimeExports.jsx( "div", { @@ -61541,7 +61529,9 @@ ${events} node: eventNode2, className: clsx(clz), eventState: transcriptState[eventId] || {}, - setEventState + setEventState: (state) => { + setEventState(state, eventId); + } } ) }, @@ -62160,7 +62150,8 @@ ${events} scrollRef }) => { const modalFooter = footer2 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "modal-footer", children: footer2 }) : ""; - scrollRef = scrollRef || reactExports.useRef(null); + const modalRef = reactExports.useRef(null); + scrollRef = scrollRef || modalRef; reactExports.useEffect(() => { if (scrollRef.current) { setTimeout(() => { @@ -62241,12 +62232,7 @@ ${events} ); }; const HtmlEntity = ({ html }) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { dangerouslySetInnerHTML: { __html: html } }); - const TitleTool = ({ - label: label2, - icon, - enabled, - onClick - }) => { + const TitleTool = ({ label: label2, icon, enabled, onClick }) => { return /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { @@ -62317,7 +62303,7 @@ ${events} break; } }, - [prevSample, nextSample] + [prevSample, nextSample, setShowingSampleDialog] ); const onHide = reactExports.useCallback(() => { setShowingSampleDialog(false); @@ -62631,9 +62617,6 @@ ${events} className: className2, listHandle } = props; - if (items.length === 0) { - return /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyPanel, { children: "No Samples" }); - } const [followOutput, setFollowOutput] = reactExports.useState(false); const [hidden2, setHidden] = reactExports.useState(false); reactExports.useEffect(() => { @@ -62661,6 +62644,31 @@ ${events} }); } }, [selectedIndex, listHandle, itemRowMapping]); + const onkeydown = reactExports.useCallback( + (e) => { + switch (e.key) { + case "ArrowUp": + prevSample(); + e.preventDefault(); + e.stopPropagation(); + break; + case "ArrowDown": + nextSample(); + e.preventDefault(); + e.stopPropagation(); + break; + case "Enter": + showSample(selectedIndex); + e.preventDefault(); + e.stopPropagation(); + break; + } + }, + [selectedIndex, nextSample, prevSample, showSample] + ); + if (items.length === 0) { + return /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyPanel, { children: "No Samples" }); + } const renderRow = (item2) => { if (item2.type === "sample") { return /* @__PURE__ */ jsxRuntimeExports.jsx( @@ -62689,28 +62697,6 @@ ${events} return null; } }; - const onkeydown = reactExports.useCallback( - (e) => { - switch (e.key) { - case "ArrowUp": - prevSample(); - e.preventDefault(); - e.stopPropagation(); - break; - case "ArrowDown": - nextSample(); - e.preventDefault(); - e.stopPropagation(); - break; - case "Enter": - showSample(selectedIndex); - e.preventDefault(); - e.stopPropagation(); - break; - } - }, - [selectedIndex] - ); const { input: input2, limit, answer: answer2, target: target2 } = gridColumns(sampleDescriptor); const sampleCount = items == null ? void 0 : items.reduce((prev2, current) => { if (current.type === "sample") { @@ -62962,7 +62948,7 @@ ${events} setSelectedSampleIndex(index2); setShowingSampleDialog(true); }, - [sampleDialogRef] + [setSelectedSampleIndex, setShowingSampleDialog] ); reactExports.useEffect(() => { if (showingSampleDialog) { @@ -63005,22 +62991,22 @@ ${events} } else { return -1; } - }, [selectedSampleIndex, items]); + }, [selectedSampleIndex, sampleItems.length]); const previousSampleIndex = reactExports.useCallback(() => { return selectedSampleIndex > 0 ? selectedSampleIndex - 1 : -1; - }, [selectedSampleIndex, items]); + }, [selectedSampleIndex]); const nextSample = reactExports.useCallback(() => { const next2 = nextSampleIndex(); if (sampleStatus !== "loading" && next2 > -1) { setSelectedSampleIndex(next2); } - }, [selectedSampleIndex, samples, sampleStatus, nextSampleIndex]); + }, [nextSampleIndex, sampleStatus, setSelectedSampleIndex]); const previousSample = reactExports.useCallback(() => { const prev2 = previousSampleIndex(); if (sampleStatus !== "loading" && prev2 > -1) { setSelectedSampleIndex(prev2); } - }, [selectedSampleIndex, samples, sampleStatus, previousSampleIndex]); + }, [previousSampleIndex, sampleStatus, setSelectedSampleIndex]); const title2 = selectedSampleIndex > -1 && sampleItems.length > selectedSampleIndex ? sampleItems[selectedSampleIndex].label : ""; if (!sampleDescriptor) { return /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyPanel, {}); @@ -63420,11 +63406,7 @@ ${events} } return count; }; - const PlanColumn = ({ - title: title2, - className: className2, - children: children2 - }) => { + const PlanColumn = ({ title: title2, className: className2, children: children2 }) => { return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx(className2), children: [ /* @__PURE__ */ jsxRuntimeExports.jsx( "div", @@ -63442,11 +63424,7 @@ ${events} children2 ] }); }; - const PlanCard = ({ - evalSpec, - evalPlan, - scores: scores2 - }) => { + const PlanCard = ({ evalSpec, evalPlan, scores: scores2 }) => { return /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { icon: ApplicationIcons.config, label: "Config" }), /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { id: "task-plan-card-body", children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlanDetailView, { evaluation: evalSpec, plan: evalPlan, scores: scores2 }) }) @@ -63850,11 +63828,7 @@ ${events} } ); }; - const StatusPanel = ({ - icon, - status, - sampleCount - }) => { + const StatusPanel = ({ icon, status, sampleCount }) => { return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.statusPanel, children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: clsx(icon, styles$2.statusIcon), style: {} }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ @@ -63882,7 +63856,7 @@ ${events} const logFileName = file ? filename(file) : ""; const handleToggle = reactExports.useCallback(() => { setOffcanvas(!offcanvas); - }, [offcanvas]); + }, [setOffcanvas, offcanvas]); return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx(styles$4.wrapper), children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs( "div", @@ -64331,9 +64305,6 @@ ${events} workspaceTabScrollPositionRef, setWorkspaceTabScrollPosition } = props; - if (!evalSpec) { - return null; - } const divRef = reactExports.useRef(null); reactExports.useEffect(() => { if (divRef.current) { @@ -64341,6 +64312,9 @@ ${events} } }, [task_id]); const resolvedTabs = useResolvedTabs(props); + if (!evalSpec) { + return void 0; + } return /* @__PURE__ */ jsxRuntimeExports.jsx( WorkSpaceView, { diff --git a/src/inspect_ai/_view/www/eslint.config.mjs b/src/inspect_ai/_view/www/eslint.config.mjs index 4b93b239a..d49deb0f1 100644 --- a/src/inspect_ai/_view/www/eslint.config.mjs +++ b/src/inspect_ai/_view/www/eslint.config.mjs @@ -1,5 +1,7 @@ -import globals from "globals"; import pluginJs from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import globals from "globals"; +import tseslint from "typescript-eslint"; export default [ { @@ -14,4 +16,25 @@ export default [ { ignores: ["libs/**", "preact/**", "dist/**"], }, + // Add TypeScript support with customized rules for all files + { + files: ["**/*.{ts,tsx}"], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + project: "./tsconfig.json", + }, + }, + plugins: { + "react-hooks": reactHooks, + }, + rules: { + // React Hooks rules + "react-hooks/rules-of-hooks": "warn", + // "react-hooks/exhaustive-deps": "warn", + + // These are disabled because we didn't have time to fix them, not because they are bad rules + "no-unused-vars": "off", + }, + }, ]; diff --git a/src/inspect_ai/_view/www/package.json b/src/inspect_ai/_view/www/package.json index 1c9f4b632..36a1d74f5 100644 --- a/src/inspect_ai/_view/www/package.json +++ b/src/inspect_ai/_view/www/package.json @@ -12,7 +12,9 @@ "dev": "vite", "prettier:check": "prettier --check src", "prettier:write": "prettier --write src", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "lint": "eslint 'src/**/*.{js,jsx,mjs,ts,tsx}'", + "lint:fix": "eslint 'src/**/*.{js,jsx,mjs,ts,tsx}' --fix" }, "exports": { ".": "./src/App.mjs" @@ -29,9 +31,11 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "eslint": "9.x", + "eslint-plugin-react-hooks": "^5.1.0", "globals": "^15.6.0", "prettier": "^3.3.3", "typescript": "^5.7.3", + "typescript-eslint": "^8.25.0", "vite": "^5.3.2" }, "dependencies": { diff --git a/src/inspect_ai/_view/www/src/App.tsx b/src/inspect_ai/_view/www/src/App.tsx index f2e2a2595..6929a141a 100644 --- a/src/inspect_ai/_view/www/src/App.tsx +++ b/src/inspect_ai/_view/www/src/App.tsx @@ -36,7 +36,7 @@ import { WorkSpace } from "./workspace/WorkSpace"; import ClipboardJS from "clipboard"; import clsx from "clsx"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ClientAPI, EvalLogHeader, @@ -72,7 +72,7 @@ interface AppProps { /** * Renders the Main Application */ -export const App: React.FC = ({ +export const App: FC = ({ api, applicationState, saveApplicationState, diff --git a/src/inspect_ai/_view/www/src/components/AnsiDisplay.tsx b/src/inspect_ai/_view/www/src/components/AnsiDisplay.tsx index 39c2ff0b6..fa4255c6e 100644 --- a/src/inspect_ai/_view/www/src/components/AnsiDisplay.tsx +++ b/src/inspect_ai/_view/www/src/components/AnsiDisplay.tsx @@ -1,14 +1,15 @@ import { ANSIColor, ANSIOutput, ANSIOutputRun, ANSIStyle } from "ansi-output"; import clsx from "clsx"; +import { CSSProperties, FC } from "react"; import "./AnsiDisplay.css"; interface ANSIDisplayProps { output: string; - style?: React.CSSProperties; + style?: CSSProperties; className?: string[] | string; } -export const ANSIDisplay: React.FC = ({ +export const ANSIDisplay: FC = ({ output, style, className, @@ -46,7 +47,7 @@ interface OutputRunProps { run: ANSIOutputRun; } -const OutputRun: React.FC = ({ run }) => { +const OutputRun: FC = ({ run }) => { // Render. return {run.text}; }; diff --git a/src/inspect_ai/_view/www/src/components/Card.tsx b/src/inspect_ai/_view/www/src/components/Card.tsx index 14d25c285..d0994eee8 100644 --- a/src/inspect_ai/_view/www/src/components/Card.tsx +++ b/src/inspect_ai/_view/www/src/components/Card.tsx @@ -1,4 +1,5 @@ import clsx from "clsx"; +import { FC, ReactNode } from "react"; import { ApplicationIcons } from "../appearance/icons"; import "./Card.css"; @@ -7,17 +8,17 @@ interface CardHeaderProps { icon?: string; label?: string; className?: string; - children?: React.ReactNode; + children?: ReactNode; } interface CardBodyProps { id?: string; - children?: React.ReactNode; + children?: ReactNode; } interface CardProps { id?: string; - children?: React.ReactNode; + children?: ReactNode; } interface CardCollapsingHeaderProps { @@ -25,10 +26,10 @@ interface CardCollapsingHeaderProps { icon: string; label: string; cardBodyId: string; - children?: React.ReactNode; + children?: ReactNode; } -export const CardHeader: React.FC = ({ +export const CardHeader: FC = ({ id, icon, label, @@ -50,7 +51,7 @@ export const CardHeader: React.FC = ({ ); }; -export const CardBody: React.FC = ({ id, children }) => { +export const CardBody: FC = ({ id, children }) => { return (
{children} @@ -58,7 +59,7 @@ export const CardBody: React.FC = ({ id, children }) => { ); }; -export const Card: React.FC = ({ id, children }) => { +export const Card: FC = ({ id, children }) => { return (
{children} @@ -66,7 +67,7 @@ export const Card: React.FC = ({ id, children }) => { ); }; -export const CardCollapsingHeader: React.FC = ({ +export const CardCollapsingHeader: FC = ({ id, icon, label, diff --git a/src/inspect_ai/_view/www/src/components/DownloadButton.tsx b/src/inspect_ai/_view/www/src/components/DownloadButton.tsx index c47446fd9..6ed80d656 100644 --- a/src/inspect_ai/_view/www/src/components/DownloadButton.tsx +++ b/src/inspect_ai/_view/www/src/components/DownloadButton.tsx @@ -1,3 +1,4 @@ +import { FC } from "react"; import api from "../api/index"; import "./DownloadButton.css"; @@ -7,7 +8,7 @@ interface DownloadButtonProps { fileContents: string | Blob | ArrayBuffer | ArrayBufferView; } -export const DownloadButton: React.FC = ({ +export const DownloadButton: FC = ({ label, fileName, fileContents, diff --git a/src/inspect_ai/_view/www/src/components/EmptyPanel.tsx b/src/inspect_ai/_view/www/src/components/EmptyPanel.tsx index 0f1d38636..d42eefd8b 100644 --- a/src/inspect_ai/_view/www/src/components/EmptyPanel.tsx +++ b/src/inspect_ai/_view/www/src/components/EmptyPanel.tsx @@ -1,10 +1,10 @@ -import { ReactNode } from "react"; +import { FC, ReactNode } from "react"; interface EmptyPanelProps { children?: ReactNode; } -export const EmptyPanel: React.FC = ({ children }) => { +export const EmptyPanel: FC = ({ children }) => { return (
diff --git a/src/inspect_ai/_view/www/src/components/ErrorPanel.tsx b/src/inspect_ai/_view/www/src/components/ErrorPanel.tsx index 96daf63ce..d9b245a38 100644 --- a/src/inspect_ai/_view/www/src/components/ErrorPanel.tsx +++ b/src/inspect_ai/_view/www/src/components/ErrorPanel.tsx @@ -1,3 +1,4 @@ +import { FC } from "react"; import { ApplicationIcons } from "../appearance/icons"; import "./ErrorPanel.css"; @@ -12,7 +13,7 @@ interface ErrorPanelProps { error: DisplayError; } -export const ErrorPanel: React.FC = ({ title, error }) => { +export const ErrorPanel: FC = ({ title, error }) => { const message = error.message; const stack = error.stack; diff --git a/src/inspect_ai/_view/www/src/components/ExpandablePanel.tsx b/src/inspect_ai/_view/www/src/components/ExpandablePanel.tsx index 8838d1200..48f5ba192 100644 --- a/src/inspect_ai/_view/www/src/components/ExpandablePanel.tsx +++ b/src/inspect_ai/_view/www/src/components/ExpandablePanel.tsx @@ -1,5 +1,13 @@ import clsx from "clsx"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { + CSSProperties, + FC, + ReactNode, + useCallback, + useEffect, + useRef, + useState, +} from "react"; import { ApplicationIcons } from "../appearance/icons"; import { useResizeObserver } from "../utils/dom"; import "./ExpandablePanel.css"; @@ -8,11 +16,11 @@ interface ExpandablePanelProps { collapse: boolean; border?: boolean; lines?: number; - children?: React.ReactNode; + children?: ReactNode; className?: string | string[]; } -export const ExpandablePanel: React.FC = ({ +export const ExpandablePanel: FC = ({ collapse, border, lines = 15, @@ -83,10 +91,10 @@ interface MoreToggleProps { collapsed: boolean; border: boolean; setCollapsed: (collapsed: boolean) => void; - style?: React.CSSProperties; + style?: CSSProperties; } -const MoreToggle: React.FC = ({ +const MoreToggle: FC = ({ collapsed, border, setCollapsed, diff --git a/src/inspect_ai/_view/www/src/components/FindBand.tsx b/src/inspect_ai/_view/www/src/components/FindBand.tsx index b08e57d6c..e14e35270 100644 --- a/src/inspect_ai/_view/www/src/components/FindBand.tsx +++ b/src/inspect_ai/_view/www/src/components/FindBand.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef } from "react"; +import { FC, KeyboardEvent, useCallback, useEffect, useRef } from "react"; import { ApplicationIcons } from "../appearance/icons"; import "./FindBand.css"; @@ -6,7 +6,7 @@ interface FindBandProps { hideBand: () => void; } -export const FindBand: React.FC = ({ hideBand }) => { +export const FindBand: FC = ({ hideBand }) => { const searchBoxRef = useRef(null); useEffect(() => { @@ -82,7 +82,7 @@ export const FindBand: React.FC = ({ hideBand }) => { ); const handleKeyDown = useCallback( - (e: React.KeyboardEvent) => { + (e: KeyboardEvent) => { if (e.key === "Escape") { hideBand(); } else if (e.key === "Enter") { diff --git a/src/inspect_ai/_view/www/src/components/HumanBaselineView.tsx b/src/inspect_ai/_view/www/src/components/HumanBaselineView.tsx index 31e4314fc..70fb62081 100644 --- a/src/inspect_ai/_view/www/src/components/HumanBaselineView.tsx +++ b/src/inspect_ai/_view/www/src/components/HumanBaselineView.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { FC, useEffect } from "react"; import { formatDateTime, formatTime } from "../utils/format"; import { AsciinemaPlayer } from "./AsciinemaPlayer"; import "./HumanBaselineView.css"; @@ -24,7 +24,7 @@ interface HumanBaselineViewProps { /** * Renders the HumanBaselineView component. */ -export const HumanBaselineView: React.FC = ({ +export const HumanBaselineView: FC = ({ started, runtime, answer, @@ -92,7 +92,7 @@ export const HumanBaselineView: React.FC = ({ answer?: string; } - const StatusMessage: React.FC = ({ + const StatusMessage: FC = ({ completed, running, answer, diff --git a/src/inspect_ai/_view/www/src/components/LabeledValue.tsx b/src/inspect_ai/_view/www/src/components/LabeledValue.tsx index c7b26b79a..a0b9b97f3 100644 --- a/src/inspect_ai/_view/www/src/components/LabeledValue.tsx +++ b/src/inspect_ai/_view/www/src/components/LabeledValue.tsx @@ -1,15 +1,16 @@ import clsx from "clsx"; +import { CSSProperties, FC, ReactNode } from "react"; interface LabeledValueProps { label: string; - style?: React.CSSProperties; - valueStyle?: React.CSSProperties; + style?: CSSProperties; + valueStyle?: CSSProperties; layout?: "column" | "row"; - children: React.ReactNode; + children: ReactNode; className?: string | string[]; } -export const LabeledValue: React.FC = ({ +export const LabeledValue: FC = ({ layout = "column", style, label, diff --git a/src/inspect_ai/_view/www/src/components/LargeModal.tsx b/src/inspect_ai/_view/www/src/components/LargeModal.tsx index 1c38862c9..5c41a6bd8 100644 --- a/src/inspect_ai/_view/www/src/components/LargeModal.tsx +++ b/src/inspect_ai/_view/www/src/components/LargeModal.tsx @@ -1,7 +1,15 @@ import clsx from "clsx"; import { ProgressBar } from "./ProgressBar"; -import { ReactNode, UIEvent, useCallback, useEffect, useRef } from "react"; +import { + FC, + ReactNode, + RefObject, + UIEvent, + useCallback, + useEffect, + useRef, +} from "react"; import styles from "./LargeModal.module.css"; export interface ModalTool { @@ -22,17 +30,17 @@ interface LargeModalProps { detail: string; detailTools?: ModalTools; showProgress: boolean; - footer?: React.ReactNode; + footer?: ReactNode; visible: boolean; onkeyup: (e: any) => void; onHide: () => void; - scrollRef: React.RefObject; - initialScrollPositionRef: React.RefObject; + scrollRef: RefObject; + initialScrollPositionRef: RefObject; setInitialScrollPosition: (position: number) => void; children: ReactNode; } -export const LargeModal: React.FC = ({ +export const LargeModal: FC = ({ id, title, detail, @@ -56,7 +64,9 @@ export const LargeModal: React.FC = ({ // Support restoring the scroll position // but only do this for the first time that the children are set - scrollRef = scrollRef || useRef(null); + const modalRef = useRef(null); + scrollRef = scrollRef || modalRef; + useEffect(() => { if (scrollRef.current) { setTimeout(() => { @@ -153,7 +163,7 @@ interface HtmlEntityProps { html: string; } -const HtmlEntity: React.FC = ({ html }) => ( +const HtmlEntity: FC = ({ html }) => ( ); @@ -164,12 +174,7 @@ interface TitleToolProps { onClick: () => void; } -const TitleTool: React.FC = ({ - label, - icon, - enabled, - onClick, -}) => { +const TitleTool: FC = ({ label, icon, enabled, onClick }) => { return (