diff --git a/site/src/pages/AgentsPage/FilesChangedPanel.stories.tsx b/site/src/pages/AgentsPage/FilesChangedPanel.stories.tsx index 0aa10268a6..02034eea61 100644 --- a/site/src/pages/AgentsPage/FilesChangedPanel.stories.tsx +++ b/site/src/pages/AgentsPage/FilesChangedPanel.stories.tsx @@ -5,6 +5,46 @@ import type { ChatDiffContents } from "api/typesGenerated"; import { expect, screen, spyOn } from "storybook/test"; import { FilesChangedPanel } from "./FilesChangedPanel"; +const sampleUnifiedDiff = `diff --git a/site/src/pages/AgentsPage/FilesChangedPanel.tsx b/site/src/pages/AgentsPage/FilesChangedPanel.tsx +index abc1234..def5678 100644 +--- a/site/src/pages/AgentsPage/FilesChangedPanel.tsx ++++ b/site/src/pages/AgentsPage/FilesChangedPanel.tsx +@@ -1,10 +1,14 @@ ++import { useTheme } from "@emotion/react"; + import { parsePatchFiles } from "@pierre/diffs"; + import { FileDiff } from "@pierre/diffs/react"; ++import { ++ DIFFS_FONT_STYLE, ++ getDiffViewerOptions, ++} from "components/ai-elements/tool/utils"; + import { chatDiffContents, chatDiffStatus } from "api/queries/chats"; + import { ErrorAlert } from "components/Alert/ErrorAlert"; + import { ScrollArea } from "components/ScrollArea/ScrollArea"; +-import { Skeleton } from "components/Skeleton/Skeleton"; + import { type FC, useMemo } from "react"; + import { useQuery } from "react-query"; +diff --git a/site/src/components/ai-elements/tool/utils.ts b/site/src/components/ai-elements/tool/utils.ts +index 1234567..abcdef0 100644 +--- a/site/src/components/ai-elements/tool/utils.ts ++++ b/site/src/components/ai-elements/tool/utils.ts +@@ -10,6 +10,18 @@ export const diffViewerCSS = + export function getDiffViewerOptions(isDark: boolean) { + return { + diffStyle: "unified" as const, ++ diffIndicators: "bars" as const, ++ overflow: "scroll" as const, + themeType: (isDark ? "dark" : "light") as "dark" | "light", ++ theme: isDark ? "github-dark-high-contrast" : "github-light", ++ unsafeCSS: diffViewerCSS, + }; + } ++ ++export const DIFFS_FONT_STYLE = { ++ "--diffs-font-size": "11px", ++ "--diffs-line-height": "1.5", ++} as React.CSSProperties; +`; + const defaultDiffStatus: ChatDiffStatusResponse = { chat_id: "test-chat", changes_requested: false, @@ -23,6 +63,13 @@ const meta: Meta = { args: { chatId: "test-chat", }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], beforeEach: () => { spyOn(API, "getChatDiffStatus").mockResolvedValue(defaultDiffStatus); spyOn(API, "getChatDiffContents").mockResolvedValue(defaultDiffContents); @@ -65,3 +112,73 @@ export const ParseError: Story = { expect(screen.getByText("No file changes to display.")).toBeInTheDocument(); }, }; + +export const WithDiffDark: Story = { + beforeEach: () => { + spyOn(API, "getChatDiffStatus").mockResolvedValue({ + ...defaultDiffStatus, + url: "https://github.com/coder/coder/pull/456", + additions: 14, + deletions: 2, + changed_files: 2, + }); + spyOn(API, "getChatDiffContents").mockResolvedValue({ + ...defaultDiffContents, + diff: sampleUnifiedDiff, + }); + }, +}; + +export const WithDiffLight: Story = { + globals: { + theme: "light", + }, + beforeEach: () => { + spyOn(API, "getChatDiffStatus").mockResolvedValue({ + ...defaultDiffStatus, + url: "https://github.com/coder/coder/pull/456", + additions: 14, + deletions: 2, + changed_files: 2, + }); + spyOn(API, "getChatDiffContents").mockResolvedValue({ + ...defaultDiffContents, + diff: sampleUnifiedDiff, + }); + }, +}; + +export const NoPullRequestDark: Story = { + beforeEach: () => { + spyOn(API, "getChatDiffStatus").mockResolvedValue({ + ...defaultDiffStatus, + url: "https://github.com/coder/coder/pull/456", + additions: 14, + deletions: 2, + changed_files: 2, + }); + spyOn(API, "getChatDiffContents").mockResolvedValue({ + ...defaultDiffContents, + diff: sampleUnifiedDiff, + }); + }, +}; + +export const NoPullRequestLight: Story = { + globals: { + theme: "light", + }, + beforeEach: () => { + spyOn(API, "getChatDiffStatus").mockResolvedValue({ + ...defaultDiffStatus, + url: "https://github.com/coder/coder/pull/456", + additions: 14, + deletions: 2, + changed_files: 2, + }); + spyOn(API, "getChatDiffContents").mockResolvedValue({ + ...defaultDiffContents, + diff: sampleUnifiedDiff, + }); + }, +}; diff --git a/site/src/pages/AgentsPage/FilesChangedPanel.tsx b/site/src/pages/AgentsPage/FilesChangedPanel.tsx index 8fdcccb981..e7021aa1bf 100644 --- a/site/src/pages/AgentsPage/FilesChangedPanel.tsx +++ b/site/src/pages/AgentsPage/FilesChangedPanel.tsx @@ -1,7 +1,12 @@ +import { useTheme } from "@emotion/react"; import { parsePatchFiles } from "@pierre/diffs"; import { FileDiff } from "@pierre/diffs/react"; import { chatDiffContents, chatDiffStatus } from "api/queries/chats"; import { ErrorAlert } from "components/Alert/ErrorAlert"; +import { + DIFFS_FONT_STYLE, + getDiffViewerOptions, +} from "components/ai-elements/tool/utils"; import { ScrollArea } from "components/ScrollArea/ScrollArea"; import { Skeleton } from "components/Skeleton/Skeleton"; import { @@ -33,6 +38,10 @@ function formatPullRequestLabel(url: string): string { } export const FilesChangedPanel: FC = ({ chatId }) => { + const theme = useTheme(); + const isDark = theme.palette.mode === "dark"; + const diffOptions = useMemo(() => getDiffViewerOptions(isDark), [isDark]); + const diffStatusQuery = useQuery(chatDiffStatus(chatId)); const diffContentsQuery = useQuery({ ...chatDiffContents(chatId), @@ -134,23 +143,14 @@ export const FilesChangedPanel: FC = ({ chatId }) => { key={fileDiff.name} fileDiff={fileDiff} options={{ - diffStyle: "unified", - diffIndicators: "bars", - overflow: "scroll", - themeType: "dark", + ...diffOptions, enableLineSelection: true, enableHoverUtility: true, onLineSelected() { // TODO: Make this add context to the input so the user can type. }, - theme: "github-dark-high-contrast", - unsafeCSS: - "pre, [data-line], [data-diffs-header] { background-color: transparent !important; } [data-diffs-header] { border-left: 1px solid var(--border); }", - }} - style={{ - "--diffs-font-size": "11px", - "--diffs-line-height": "1.5", }} + style={DIFFS_FONT_STYLE} /> ))}