various hitl buffs (#3828)
This commit is contained in:
@@ -4,16 +4,26 @@ import { Button } from "@/components/ui/button";
|
||||
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
||||
import { cn } from "@/util/utils";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
|
||||
import { HumanInteractionBlock } from "../types/workflowTypes";
|
||||
import { WorkflowRunBlock } from "../types/workflowRunTypes";
|
||||
|
||||
interface Props {
|
||||
humanInteractionBlock: HumanInteractionBlock;
|
||||
workflowRunBlock: WorkflowRunBlock;
|
||||
}
|
||||
|
||||
export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
|
||||
export function WorkflowRunHumanInteraction({ workflowRunBlock }: Props) {
|
||||
const credentialGetter = useCredentialGetter();
|
||||
const queryClient = useQueryClient();
|
||||
const { data: workflowRun } = useWorkflowRunQuery();
|
||||
@@ -21,11 +31,14 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
|
||||
workflowRun && workflowRun.status === WorkflowRunStatus.Paused;
|
||||
|
||||
const buttonLayout =
|
||||
humanInteractionBlock.positive_descriptor.length < 8 &&
|
||||
humanInteractionBlock.negative_descriptor.length < 8
|
||||
(workflowRunBlock.positive_descriptor?.length ?? 0) < 8 &&
|
||||
(workflowRunBlock.negative_descriptor?.length ?? 0) < 8
|
||||
? "inline"
|
||||
: "stacked";
|
||||
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
const [choice, setChoice] = useState<"approve" | "reject" | null>(null);
|
||||
|
||||
const approveMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!workflowRun) {
|
||||
@@ -45,8 +58,8 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
|
||||
|
||||
toast({
|
||||
variant: "success",
|
||||
title: `${humanInteractionBlock.positive_descriptor}`,
|
||||
description: `Successfully chose: ${humanInteractionBlock.positive_descriptor}`,
|
||||
title: `${workflowRunBlock.positive_descriptor}`,
|
||||
description: `Successfully chose: ${workflowRunBlock.positive_descriptor}`,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
@@ -77,8 +90,8 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
|
||||
|
||||
toast({
|
||||
variant: "success",
|
||||
title: `${humanInteractionBlock.negative_descriptor}`,
|
||||
description: `Successfully chose: ${humanInteractionBlock.negative_descriptor}`,
|
||||
title: `${workflowRunBlock.negative_descriptor}`,
|
||||
description: `Successfully chose: ${workflowRunBlock.negative_descriptor}`,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
@@ -96,18 +109,60 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
|
||||
|
||||
return (
|
||||
<div className="mt-4 flex flex-col gap-4 rounded-md bg-slate-elevation4 p-4">
|
||||
<div className="text-sm">{humanInteractionBlock.instructions}</div>
|
||||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{choice === "approve"
|
||||
? workflowRunBlock.positive_descriptor
|
||||
: workflowRunBlock.negative_descriptor}
|
||||
</DialogTitle>
|
||||
<DialogDescription>Are you sure?</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">Back</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
variant={choice === "reject" ? "destructive" : "default"}
|
||||
onClick={() => {
|
||||
if (choice === "approve") {
|
||||
approveMutation.mutate();
|
||||
} else if (choice === "reject") {
|
||||
rejectMutation.mutate();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Proceed
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<div className="text-sm">{workflowRunBlock.instructions}</div>
|
||||
<div
|
||||
className={cn("flex gap-2", {
|
||||
"justify-between": buttonLayout === "inline",
|
||||
"flex-col": buttonLayout === "stacked",
|
||||
})}
|
||||
>
|
||||
<Button variant="destructive" onClick={() => rejectMutation.mutate()}>
|
||||
<div>{humanInteractionBlock.negative_descriptor}</div>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
setChoice("reject");
|
||||
setIsDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
<div>{workflowRunBlock.negative_descriptor}</div>
|
||||
</Button>
|
||||
<Button variant="default" onClick={() => approveMutation.mutate()}>
|
||||
<div>{humanInteractionBlock.positive_descriptor}</div>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => {
|
||||
setChoice("approve");
|
||||
setIsDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
<div>{workflowRunBlock.positive_descriptor}</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
ExternalLinkIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { useCallback } from "react";
|
||||
import { useParams, Link } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { Status } from "@/api/types";
|
||||
import { formatDuration, toDuration } from "@/routes/workflows/utils";
|
||||
@@ -27,13 +27,8 @@ import {
|
||||
WorkflowRunOverviewActiveElement,
|
||||
} from "./WorkflowRunOverview";
|
||||
import { ThoughtCard } from "./ThoughtCard";
|
||||
import { useWorkflowQuery } from "../hooks/useWorkflowQuery";
|
||||
import { ObserverThought } from "../types/workflowRunTypes";
|
||||
import {
|
||||
HumanInteractionBlock,
|
||||
isTaskVariantBlock,
|
||||
type WorkflowApiResponse,
|
||||
} from "../types/workflowTypes";
|
||||
import { isTaskVariantBlock } from "../types/workflowTypes";
|
||||
import { WorkflowRunHumanInteraction } from "./WorkflowRunHumanInteraction";
|
||||
|
||||
type Props = {
|
||||
@@ -45,28 +40,6 @@ type Props = {
|
||||
onThoughtCardClick: (thought: ObserverThought) => void;
|
||||
};
|
||||
|
||||
const getHumanInteractionBlock = (
|
||||
block: WorkflowRunBlock,
|
||||
workflow?: WorkflowApiResponse,
|
||||
): HumanInteractionBlock | null => {
|
||||
if (block.block_type !== "human_interaction") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!workflow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blocks = workflow.workflow_definition.blocks;
|
||||
const candidate = blocks.find((b) => b.label === block.label);
|
||||
|
||||
if (!candidate || candidate.block_type !== "human_interaction") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidate as HumanInteractionBlock;
|
||||
};
|
||||
|
||||
function WorkflowRunTimelineBlockItem({
|
||||
activeItem,
|
||||
block,
|
||||
@@ -75,12 +48,6 @@ function WorkflowRunTimelineBlockItem({
|
||||
onActionClick,
|
||||
onThoughtCardClick,
|
||||
}: Props) {
|
||||
const { workflowPermanentId } = useParams();
|
||||
const { data: workflow } = useWorkflowQuery({
|
||||
workflowPermanentId,
|
||||
});
|
||||
|
||||
const humanInteractionBlock = getHumanInteractionBlock(block, workflow);
|
||||
const actions = block.actions ?? [];
|
||||
|
||||
const hasActiveAction =
|
||||
@@ -203,10 +170,8 @@ function WorkflowRunTimelineBlockItem({
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{humanInteractionBlock && (
|
||||
<WorkflowRunHumanInteraction
|
||||
humanInteractionBlock={humanInteractionBlock}
|
||||
/>
|
||||
{block.block_type === "human_interaction" && (
|
||||
<WorkflowRunHumanInteraction workflowRunBlock={block} />
|
||||
)}
|
||||
|
||||
{actions.map((action, index) => {
|
||||
|
||||
Reference in New Issue
Block a user