171 lines
4.8 KiB
TypeScript
171 lines
4.8 KiB
TypeScript
import { Button } from "@/components/ui/button";
|
|
import { ThreadIdCopyable } from "./thread-id";
|
|
import { InboxItemInput } from "./inbox-item-input";
|
|
import useInterruptedActions from "../hooks/use-interrupted-actions";
|
|
import { cn } from "@/lib/utils";
|
|
import { toast } from "sonner";
|
|
import { useQueryState } from 'nuqs'
|
|
import { constructOpenInStudioURL } from "../utils";
|
|
import { HumanInterrupt } from "@langchain/langgraph/prebuilt";
|
|
|
|
interface ThreadActionsViewProps {
|
|
interrupt: HumanInterrupt;
|
|
handleShowSidePanel: (showState: boolean, showDescription: boolean) => void;
|
|
showState: boolean;
|
|
showDescription: boolean;
|
|
}
|
|
|
|
function ButtonGroup({
|
|
handleShowState,
|
|
handleShowDescription,
|
|
showingState,
|
|
showingDescription,
|
|
}: {
|
|
handleShowState: () => void;
|
|
handleShowDescription: () => void;
|
|
showingState: boolean;
|
|
showingDescription: boolean;
|
|
}) {
|
|
return (
|
|
<div className="flex flex-row gap-0 items-center justify-center">
|
|
<Button
|
|
variant="outline"
|
|
className={cn(
|
|
"rounded-l-md rounded-r-none border-r-[0px]",
|
|
showingState ? "text-black" : "bg-white",
|
|
)}
|
|
size="sm"
|
|
onClick={handleShowState}
|
|
>
|
|
State
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
className={cn(
|
|
"rounded-l-none rounded-r-md border-l-[0px]",
|
|
showingDescription ? "text-black" : "bg-white",
|
|
)}
|
|
size="sm"
|
|
onClick={handleShowDescription}
|
|
>
|
|
Description
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function ThreadActionsView({
|
|
interrupt,
|
|
handleShowSidePanel,
|
|
showDescription,
|
|
showState,
|
|
}: ThreadActionsViewProps) {
|
|
const [threadId] = useQueryState("threadId");
|
|
const {
|
|
acceptAllowed,
|
|
hasEdited,
|
|
hasAddedResponse,
|
|
streaming,
|
|
supportsMultipleMethods,
|
|
streamFinished,
|
|
loading,
|
|
handleSubmit,
|
|
handleIgnore,
|
|
handleResolve,
|
|
setSelectedSubmitType,
|
|
setHasAddedResponse,
|
|
setHasEdited,
|
|
humanResponse,
|
|
setHumanResponse,
|
|
initialHumanInterruptEditValue,
|
|
} = useInterruptedActions({
|
|
interrupt,
|
|
});
|
|
const [apiUrl] = useQueryState("apiUrl");
|
|
|
|
const handleOpenInStudio = () => {
|
|
if (!apiUrl) {
|
|
toast.error("Error", {
|
|
description: "Please set the LangGraph deployment URL in settings.",
|
|
duration: 5000,
|
|
richColors: true,
|
|
closeButton: true,
|
|
});
|
|
return;
|
|
}
|
|
|
|
const studioUrl = constructOpenInStudioURL(apiUrl, threadId ?? undefined);
|
|
window.open(studioUrl, "_blank");
|
|
};
|
|
|
|
const threadTitle = interrupt.action_request.action || "Unknown";
|
|
const actionsDisabled = loading || streaming;
|
|
|
|
return (
|
|
<div className="flex flex-col min-h-full w-full gap-9">
|
|
{/* Header */}
|
|
<div className="flex flex-wrap items-center justify-between w-full gap-3">
|
|
<div className="flex items-center justify-start gap-3">
|
|
<p className="text-2xl tracking-tighter text-pretty">{threadTitle}</p>
|
|
{threadId && <ThreadIdCopyable threadId={threadId} />}
|
|
</div>
|
|
<div className="flex flex-row gap-2 items-center justify-start">
|
|
{apiUrl && (
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
className="flex items-center gap-1 bg-white"
|
|
onClick={handleOpenInStudio}
|
|
>
|
|
Studio
|
|
</Button>
|
|
)}
|
|
<ButtonGroup
|
|
handleShowState={() => handleShowSidePanel(true, false)}
|
|
handleShowDescription={() => handleShowSidePanel(false, true)}
|
|
showingState={showState}
|
|
showingDescription={showDescription}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-row gap-2 items-center justify-start w-full">
|
|
<Button
|
|
variant="outline"
|
|
className="text-gray-800 border-gray-500 font-normal bg-white"
|
|
onClick={handleResolve}
|
|
disabled={actionsDisabled}
|
|
>
|
|
Mark as Resolved
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
className="text-gray-800 border-gray-500 font-normal bg-white"
|
|
onClick={handleIgnore}
|
|
disabled={actionsDisabled}
|
|
>
|
|
Ignore
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<InboxItemInput
|
|
acceptAllowed={acceptAllowed}
|
|
hasEdited={hasEdited}
|
|
hasAddedResponse={hasAddedResponse}
|
|
interruptValue={interrupt}
|
|
humanResponse={humanResponse}
|
|
initialValues={initialHumanInterruptEditValue.current}
|
|
setHumanResponse={setHumanResponse}
|
|
streaming={streaming}
|
|
streamFinished={streamFinished}
|
|
supportsMultipleMethods={supportsMultipleMethods}
|
|
setSelectedSubmitType={setSelectedSubmitType}
|
|
setHasAddedResponse={setHasAddedResponse}
|
|
setHasEdited={setHasEdited}
|
|
handleSubmit={handleSubmit}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|