Skip to content

Commit

Permalink
feat(frontend): Create push to Github action button in chat interface (
Browse files Browse the repository at this point in the history
  • Loading branch information
amanape authored Nov 15, 2024
1 parent 5b3db1b commit 1acb66c
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
5 changes: 5 additions & 0 deletions frontend/__tests__/components/chat/chat-interface.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ describe("Empty state", () => {
}));

beforeAll(() => {
vi.mock("@remix-run/react", async (importActual) => ({
...(await importActual<typeof import("@remix-run/react")>()),
useRouteLoaderData: vi.fn(() => ({})),
}));

vi.mock("#/context/socket", async (importActual) => ({
...(await importActual<typeof import("#/context/ws-client-provider")>()),
useWsClient: useWsClientMock,
Expand Down
46 changes: 46 additions & 0 deletions frontend/src/components/chat-interface.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useDispatch, useSelector } from "react-redux";
import React from "react";
import posthog from "posthog-js";
import { useRouteLoaderData } from "@remix-run/react";
import { convertImageToBase64 } from "#/utils/convert-image-to-base-64";
import { ChatMessage } from "./chat-message";
import { FeedbackActions } from "./feedback-actions";
Expand All @@ -26,6 +27,9 @@ import {
WsClientProviderStatus,
} from "#/context/ws-client-provider";
import OpenHands from "#/api/open-hands";
import { clientLoader } from "#/routes/_oh";
import { downloadWorkspace } from "#/utils/download-workspace";
import { SuggestionItem } from "./suggestion-item";

const isErrorMessage = (
message: Message | ErrorMessage,
Expand All @@ -38,6 +42,7 @@ export function ChatInterface() {
const scrollRef = React.useRef<HTMLDivElement>(null);
const { scrollDomToBottom, onChatBodyScroll, hitBottom } =
useScrollToBottom(scrollRef);
const rootLoaderData = useRouteLoaderData<typeof clientLoader>("routes/_oh");

const { messages } = useSelector((state: RootState) => state.chat);
const { curAgentState } = useSelector((state: RootState) => state.agent);
Expand All @@ -47,6 +52,7 @@ export function ChatInterface() {
>("positive");
const [feedbackModalIsOpen, setFeedbackModalIsOpen] = React.useState(false);
const [messageToSend, setMessageToSend] = React.useState<string | null>(null);
const [isDownloading, setIsDownloading] = React.useState(false);

React.useEffect(() => {
if (status === WsClientProviderStatus.ACTIVE) {
Expand Down Expand Up @@ -94,6 +100,17 @@ export function ChatInterface() {
setFeedbackPolarity(polarity);
};

const handleDownloadWorkspace = async () => {
setIsDownloading(true);
try {
await downloadWorkspace();
} catch (error) {
// TODO: Handle error
} finally {
setIsDownloading(false);
}
};

return (
<div className="h-full flex flex-col justify-between">
{messages.length === 0 && (
Expand Down Expand Up @@ -128,6 +145,7 @@ export function ChatInterface() {
<div className="w-6 h-6 border-2 border-t-[4px] border-primary-500 rounded-full animate-spin" />
</div>
)}

{!isLoadingMessages &&
messages.map((message, index) =>
isErrorMessage(message) ? (
Expand All @@ -153,6 +171,34 @@ export function ChatInterface() {
</ChatMessage>
),
)}

{(curAgentState === AgentState.AWAITING_USER_INPUT ||
curAgentState === AgentState.FINISHED) && (
<div className="flex flex-col gap-2 mb-2">
{rootLoaderData?.ghToken ? (
<SuggestionItem
suggestion={{
label: "Push to GitHub",
value:
"Please push the changes to GitHub and open a pull request.",
}}
onClick={(value) => {
handleSendMessage(value, []);
}}
/>
) : (
<SuggestionItem
suggestion={{
label: !isDownloading
? "Download .zip"
: "Downloading, please wait...",
value: "Download .zip",
}}
onClick={handleDownloadWorkspace}
/>
)}
</div>
)}
</div>

<div className="flex flex-col gap-[6px] px-4 pb-4">
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/suggestion-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ interface SuggestionItemProps {

export function SuggestionItem({ suggestion, onClick }: SuggestionItemProps) {
return (
<li className="border border-neutral-600 rounded-xl hover:bg-neutral-700">
<li className="list-none border border-neutral-600 rounded-xl hover:bg-neutral-700">
<button
type="button"
data-testid="suggestion"
onClick={() => onClick(suggestion.value)}
className="text-[16px] leading-6 -tracking-[0.01em] text-center w-full p-4 font-semibold"
className="text-[16px] leading-6 -tracking-[0.01em] text-center w-full p-3 font-semibold"
>
{suggestion.label}
</button>
Expand Down

0 comments on commit 1acb66c

Please sign in to comment.