diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 3cf34d91..e8069aa3 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,5 +1,7 @@ import type { Preview } from "@storybook/react"; import "@radix-ui/themes/styles.css"; +import "../src/lib/render/web.css"; + import { initialize, mswLoader } from "msw-storybook-addon"; initialize(); diff --git a/src/__fixtures__/chat_links_response.ts b/src/__fixtures__/chat_links_response.ts index f2fecc5f..53dcab5d 100644 --- a/src/__fixtures__/chat_links_response.ts +++ b/src/__fixtures__/chat_links_response.ts @@ -6,10 +6,19 @@ export const STUB_LINKS_FOR_CHAT_RESPONSE: LinksForChatResponse = { text: "Save and return", action: "patch-all", goto: "SETTINGS:/path/to/config/file.yaml", + link_tooltip: "", + }, + { + text: "Can you fix it?", + action: "follow-up", + link_tooltip: "a nice tool tip message", + }, + { text: 'git commit -m "message"', action: "commit", link_tooltip: "" }, + { text: "Save and return", goto: "SETTINGS:postgres", link_tooltip: "" }, + { + text: "Investigate Project", + action: "summarize-project", + link_tooltip: "", }, - { text: "Can you fix it?", action: "follow-up" }, - { text: 'git commit -m "message"', action: "commit" }, - { text: "Save and return", goto: "SETTINGS:postgres" }, - { text: "Investigate Project", action: "summarize-project" }, ], }; diff --git a/src/components/ChatContent/ChatContent.tsx b/src/components/ChatContent/ChatContent.tsx index 6d783cd6..7e9ba444 100644 --- a/src/components/ChatContent/ChatContent.tsx +++ b/src/components/ChatContent/ChatContent.tsx @@ -1,8 +1,6 @@ -import React, { useCallback, useRef, useMemo } from "react"; +import React, { useCallback, useRef } from "react"; import { ChatMessages, - diffApi, - isAssistantMessage, isChatContextFileMessage, isDiffMessage, isToolMessage, @@ -122,20 +120,6 @@ export const ChatContent: React.FC = ({ const thread = useAppSelector(selectThread); const isConfig = !!thread.integration; const isWaiting = useAppSelector(selectIsWaiting); - const [applyAll, applyAllResult] = - diffApi.useApplyAllPatchesInMessagesMutation(); - - const hasPins = useMemo( - () => - messages.some((message) => { - if (!isAssistantMessage(message)) return false; - if (!message.content) return false; - return message.content - .split("\n") - .some((line) => line.startsWith("📍")); - }), - [messages], - ); const { handleScroll, @@ -170,13 +154,6 @@ export const ChatContent: React.FC = ({ thread.integration?.path, ]); - const handleSaveAndReturn = useCallback(async () => { - const result = await applyAll(messages); - if (!result.error) { - handleReturnToConfigurationClick(); - } - }, [applyAll, handleReturnToConfigurationClick, messages]); - return ( = ({ Return )} - - {isConfig && hasPins && ( - - )} ); diff --git a/src/components/ChatContent/ContextFiles.tsx b/src/components/ChatContent/ContextFiles.tsx index 46402461..f83fddf1 100644 --- a/src/components/ChatContent/ContextFiles.tsx +++ b/src/components/ChatContent/ContextFiles.tsx @@ -147,7 +147,7 @@ export const ContextFiles: React.FC<{ - + 📎 {fileNames.join(", ")} diff --git a/src/components/ChatContent/ToolsContent.tsx b/src/components/ChatContent/ToolsContent.tsx index 3e0b8005..24980389 100644 --- a/src/components/ChatContent/ToolsContent.tsx +++ b/src/components/ChatContent/ToolsContent.tsx @@ -406,7 +406,12 @@ const ToolUsageSummary: React.FC<{ }) => { return ( - + 🔨{" "} {toolUsageAmount.map(({ functionName, amountOfCalls }, index) => ( diff --git a/src/components/ChatLinks/ChatLinks.tsx b/src/components/ChatLinks/ChatLinks.tsx index 6ffb4946..9d435f6f 100644 --- a/src/components/ChatLinks/ChatLinks.tsx +++ b/src/components/ChatLinks/ChatLinks.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { Flex, Button, Heading, Container, Box } from "@radix-ui/themes"; +import { Flex, Button, Container, Box } from "@radix-ui/themes"; import { linksApi, type ChatLink } from "../../services/refact/links"; import { diffApi, isUserMessage } from "../../services/refact"; import { @@ -20,6 +20,8 @@ import { setIntegrationData, } from "../../features/Chat"; import { popBackTo } from "../../features/Pages/pagesSlice"; +import { Spinner } from "@radix-ui/themes"; +import { TruncateRight } from "../Text/TruncateRight"; function maybeConcatActionAndGoToStrings(link: ChatLink): string | undefined { const hasAction = "action" in link; @@ -82,8 +84,12 @@ export const ChatLinks: React.FC = () => { popBackTo({ name: "integrations page", // projectPath: isFile ? payload : "", - integrationName: !isFile ? payload : "", - integrationPath: isFile ? payload : "", + integrationName: + !isFile && payload !== "DEFAULT" + ? payload + : maybeIntegration?.name, + integrationPath: isFile ? payload : maybeIntegration?.path, + projectPath: maybeIntegration?.project, }), ); // TODO: open in the integrations @@ -99,8 +105,17 @@ export const ChatLinks: React.FC = () => { const handleLinkAction = (link: ChatLink) => { if (!("action" in link)) return; + if (link.action === "goto" && "goto" in link) { + handleGoTo(link.goto); + return; + } + if (link.action === "patch-all") { - void applyPatches(messages); + void applyPatches(messages).then(() => { + if ("goto" in link) { + handleGoTo(link.goto); + } + }); return; } @@ -118,26 +133,22 @@ export const ChatLinks: React.FC = () => { return; } - if (link.action === "commit") { - // TODO: there should be an endpoint for this - void applyPatches(messages).then(() => { - if ("goto" in link && link.goto) { - handleGoTo(link.goto); - } - }); + // if (link.action === "commit") { + // // TODO: there should be an endpoint for this + // void applyPatches(messages).then(() => { + // if ("goto" in link && link.goto) { + // handleGoTo(link.goto); + // } + // }); - return; - } + // return; + // } // eslint-disable-next-line no-console console.warn(`unknown action: ${JSON.stringify(link)}`); }; const handleClick = (link: ChatLink) => { - if (!("action" in link) && "goto" in link) { - handleGoTo(link.goto); - } else { - handleLinkAction(link); - } + handleLinkAction(link); }; const skipLinksRequest = useMemo(() => { @@ -161,32 +172,46 @@ export const ChatLinks: React.FC = () => { // TODO: waiting, errors, maybe add a title - if (!linksResult.data || isStreaming || isWaiting || unCalledTools) { + if (isStreaming || isWaiting || unCalledTools) { return null; } const Wrapper = messages.length === 0 ? Box : Container; - return ( - - - Available Actions:{" "} - - - - {linksResult.data.links.map((link, index) => { - const key = `chat-link-${index}`; - return ; - })} - - - ); + + if (linksResult.isLoading) { + return ( + + + + ); + } + + if (linksResult.data && linksResult.data.links.length > 0) { + return ( + + + {linksResult.data.links.map((link, index) => { + const key = `chat-link-${index}`; + return ( + + ); + })} + + + ); + } + + return null; }; const ChatLinkButton: React.FC<{ link: ChatLink; onClick: (link: ChatLink) => void; }> = ({ link, onClick }) => { - const title = maybeConcatActionAndGoToStrings(link); + const title = link.link_tooltip || maybeConcatActionAndGoToStrings(link); const handleClick = React.useCallback(() => onClick(link), [link, onClick]); return ( @@ -196,11 +221,13 @@ const ChatLinkButton: React.FC<{ // variant="outline" // variant="soft" // variant="ghost" + variant="surface" title={title} onClick={handleClick} + style={{ maxWidth: "100%" }} > - {link.text} + {link.text} ); }; diff --git a/src/components/Toolbar/Toolbar.tsx b/src/components/Toolbar/Toolbar.tsx index d57b5d97..c354cd60 100644 --- a/src/components/Toolbar/Toolbar.tsx +++ b/src/components/Toolbar/Toolbar.tsx @@ -145,6 +145,7 @@ export const Toolbar = ({ activeTab }: ToolbarProps) => { active={isDashboardTab(activeTab)} ref={(x) => refs.setBack(x)} onClick={() => goToTab({ type: "dashboard" })} + style={{ cursor: "pointer" }} > {windowWidth < 400 || shouldCollapse ? : "Home"} @@ -158,7 +159,7 @@ export const Toolbar = ({ activeTab }: ToolbarProps) => { active={isActive} key={chat.id} onClick={() => goToTab({ type: "chat", id: chat.id })} - style={{ minWidth: 0, maxWidth: "140px" }} + style={{ minWidth: 0, maxWidth: "140px", cursor: "pointer" }} ref={isActive ? setFocus : undefined} title={chat.title} > diff --git a/src/lib/render/web.css b/src/lib/render/web.css index d8ee9929..1da8e7d4 100644 --- a/src/lib/render/web.css +++ b/src/lib/render/web.css @@ -7,3 +7,9 @@ body { width: 260px; flex-shrink: 0; } + +.radix-themes { + --cursor-button: pointer; + --cursor-menu-item: pointer; + --cursor-link: pointer; +} diff --git a/src/services/refact/links.ts b/src/services/refact/links.ts index 745bdc90..a26f4847 100644 --- a/src/services/refact/links.ts +++ b/src/services/refact/links.ts @@ -11,11 +11,20 @@ import { CHAT_LINKS_URL } from "./consts"; // link_action // link_tooltip export type ChatLink = - | { text: string; goto: string; action: string } - | { text: string; goto: string /* action: undefined */ } - | { text: string; /* goto: undefined; */ action: string } - | { text: string; goto: string; action: "go-to" } - | { text: string; action: "summarize-project"; current_config_file?: string }; + | { text: string; goto: string; action: string; link_tooltip: string } + | { text: string; goto: string; link_tooltip: string /* action: undefined */ } + | { + text: string; + /* goto: undefined; */ action: string; + link_tooltip: string; + } + | { text: string; goto: string; action: "go-to"; link_tooltip: string } + | { + text: string; + action: "summarize-project"; + current_config_file?: string; + link_tooltip: string; + }; function isChatLink(json: unknown): json is ChatLink { if (!json || typeof json !== "object") return false;