Merge remote-tracking branch 'origin/ioView' into zustand/io/migration

This commit is contained in:
Lucas Oliveira 2024-02-26 18:42:28 +01:00
commit cb63d5be2d
9 changed files with 259 additions and 261 deletions

View file

@ -168,6 +168,7 @@ export default function GenericNode({
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null validationStatus: validationStatusType | null
) => { ) => {
console.log(buildStatus);
const isValid = validationStatus && validationStatus.valid; const isValid = validationStatus && validationStatus.valid;
if (isValid) { if (isValid) {
return "green-status"; return "green-status";
@ -193,7 +194,6 @@ export default function GenericNode({
}; };
const renderIconPlayOrPauseComponents = ( const renderIconPlayOrPauseComponents = (
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => { ) => {
if (buildStatus === BuildStatus.BUILDING) { if (buildStatus === BuildStatus.BUILDING) {
return <Loading />; return <Loading />;
@ -201,7 +201,7 @@ export default function GenericNode({
return ( return (
<IconComponent <IconComponent
name="Play" name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-muted-foreground hover:text-medium-indigo" className="absolute ml-0.5 h-5 fill-current stroke-2 text-muted-foreground group-hover:text-medium-indigo"
/> />
); );
} }
@ -468,44 +468,21 @@ export default function GenericNode({
variant="secondary" variant="secondary"
className={"group h-9 px-1.5"} className={"group h-9 px-1.5"}
onClick={() => { onClick={() => {
if (buildStatus === BuildStatus.BUILDING || isBuilding) if (data?.buildStatus === BuildStatus.BUILDING || isBuilding)
return; return;
buildFlow(data.id); buildFlow(data.id);
}} }}
> >
<div> <div>
<ShadTooltip <ShadTooltip
styleClasses="cursor-default"
content={ content={
buildStatus === BuildStatus.BUILDING ? ( "Build"
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">
Build{" "}
<IconComponent
name="Play"
className=" h-5 stroke-status-green stroke-2"
/>{" "}
flow to validate status.
</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? `${durationString}\n${validationStatus.params}`
.split("\n")
.map((line, index) => (
<div key={index}>{line}</div>
))
: durationString}
</div>
)
} }
side="bottom" side="bottom"
> >
<div className="generic-node-status-position flex items-center justify-center"> <div className="generic-node-status-position flex items-center justify-center">
{renderIconPlayOrPauseComponents( {renderIconPlayOrPauseComponents(
buildStatus, buildStatus,
validationStatus
)} )}
</div> </div>
</ShadTooltip> </ShadTooltip>
@ -514,7 +491,6 @@ export default function GenericNode({
)} )}
<div className=""> <div className="">
<ShadTooltip <ShadTooltip
styleClasses="cursor-default"
content={ content={
data?.buildStatus === BuildStatus.BUILDING ? ( data?.buildStatus === BuildStatus.BUILDING ? (
<span>Building...</span> <span>Building...</span>
@ -530,7 +506,6 @@ export default function GenericNode({
</div> </div>
) )
} }
side="bottom"
> >
<div> <div>
{renderIconStatusComponents( {renderIconStatusComponents(

View file

@ -1,7 +1,11 @@
import { cloneDeep } from "lodash";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants"; import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants";
import BaseModal from "../../modals/baseModal"; import BaseModal from "../../modals/baseModal";
import useAlertStore from "../../stores/alertStore";
import useFlowStore from "../../stores/flowStore"; import useFlowStore from "../../stores/flowStore";
import { NodeType } from "../../types/flow";
import { validateNodes } from "../../utils/reactflowUtils";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import AccordionComponent from "../AccordionComponent"; import AccordionComponent from "../AccordionComponent";
import IOInputField from "../IOInputField"; import IOInputField from "../IOInputField";
@ -16,19 +20,22 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
const inputs = useFlowStore((state) => state.inputs).filter( const inputs = useFlowStore((state) => state.inputs).filter(
(input) => input.type !== "ChatInput" (input) => input.type !== "ChatInput"
); );
const chatInput = useFlowStore((state) => state.inputs).find(
(input) => input.type === "ChatInput"
);
const outputs = useFlowStore((state) => state.outputs).filter( const outputs = useFlowStore((state) => state.outputs).filter(
(output) => output.type !== "ChatOutput" (output) => output.type !== "ChatOutput"
); );
const chatOutput = useFlowStore((state) => state.outputs).find(
(output) => output.type === "ChatOutput"
);
const nodes = useFlowStore((state) => state.nodes).filter( const nodes = useFlowStore((state) => state.nodes).filter(
(node) => (node) =>
(inputs.some((input) => input.id === node.id) || (inputs.some((input) => input.id === node.id) ||
outputs.some((output) => output.id === node.id)) && outputs.some((output) => output.id === node.id))
node.type !== "ChatInput" &&
node.type !== "ChatOutput"
);
const haveChat = useFlowStore((state) => state.outputs).some(
(output) => output.type === "ChatOutput"
); );
const haveChat =
chatInput || chatOutput
const [selectedTab, setSelectedTab] = useState( const [selectedTab, setSelectedTab] = useState(
inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0 inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0
); );
@ -36,6 +43,45 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
{ type: string; id: string } | undefined { type: string; id: string } | undefined
>(undefined); >(undefined);
const { getNode, setNode, buildFlow, getFlow } = useFlowStore();
const { setErrorData } = useAlertStore();
const setIsBuilding = useFlowStore((state) => state.setIsBuilding);
const [lockChat, setLockChat] = useState(false);
const [chatValue, setChatValue] = useState("");
const isBuilding = useFlowStore((state) => state.isBuilding);
async function sendMessage(count = 1): Promise<void> {
if (isBuilding) return;
const { nodes, edges } = getFlow();
let nodeValidationErrors = validateNodes(nodes, edges);
if (nodeValidationErrors.length === 0) {
setIsBuilding(true);
setLockChat(true);
setChatValue("");
const chatInputNode = nodes.find((node) => node.id === chatInput?.id);
if (chatInputNode) {
let newNode = cloneDeep(chatInputNode);
newNode.data.node!.template["message"].value = chatValue;
setNode(chatInput!.id, newNode);
}
for (let i = 0; i < count; i++) {
await buildFlow().catch((err) => {
console.error(err);
setLockChat(false);
});
}
setLockChat(false);
//set chat message in the flow and run build
//@ts-ignore
} else {
setErrorData({
title: "Oops! Looks like you missed some required information:",
list: nodeValidationErrors,
});
}
}
useEffect(() => { useEffect(() => {
setSelectedViewField(undefined); setSelectedViewField(undefined);
setSelectedTab(inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0); setSelectedTab(inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0);
@ -43,7 +89,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
return ( return (
<BaseModal <BaseModal
size={haveChat ? "large" : "small"} size={haveChat ? (selectedTab === 0 ? "large-thin" : "large") : "small"}
open={open} open={open}
setOpen={setOpen} setOpen={setOpen}
> >
@ -60,7 +106,8 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
</div> </div>
</BaseModal.Header> </BaseModal.Header>
<BaseModal.Content> <BaseModal.Content>
<div className="flex-max-width mt-2 h-[80vh]"> <div className="flex h-full flex-col">
<div className="flex-max-width mt-2 h-full">
{selectedTab !== 0 && ( {selectedTab !== 0 && (
<div <div
className={cn( className={cn(
@ -70,7 +117,9 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
> >
<Tabs <Tabs
value={selectedTab.toString()} value={selectedTab.toString()}
className={"api-modal-tabs "} className={
"flex h-full flex-col overflow-hidden rounded-md border bg-muted text-center"
}
onValueChange={(value) => { onValueChange={(value) => {
setSelectedTab(Number(value)); setSelectedTab(Number(value));
}} }}
@ -226,12 +275,27 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
/> />
) )
) : ( ) : (
<NewChatView /> <NewChatView
sendMessage={sendMessage}
chatValue={chatValue}
setChatValue={setChatValue}
lockChat={lockChat}
setLockChat={setLockChat}
/>
) )
) : ( ) : (
<div className="absolute bottom-8 right-8"> <div className="absolute bottom-8 right-8"></div>
<Button className="px-3"> )}
<IconComponent name="Play" className="h-6 w-6" /> </div>
{!haveChat && (
<div className="flex w-full justify-end pt-6">
<Button variant={"outline"} className="px-3 flex gap-2" onClick={() => sendMessage(1)}>
<IconComponent
name={isBuilding ? "Loader2" : "Play"}
className={cn("h-4 w-4", isBuilding ? "animate-spin" : "fill-current text-medium-indigo")}
/>
Run Flow
</Button> </Button>
</div> </div>
)} )}

View file

@ -21,7 +21,7 @@ export default function ChatTrigger({}): JSX.Element {
> >
<div className="flex gap-3"> <div className="flex gap-3">
<IconComponent <IconComponent
name="Sliders" name="Zap"
className={"message-button-icon h-6 w-6 transition-all"} className={"message-button-icon h-6 w-6 transition-all"}
/> />
</div> </div>

View file

@ -70,7 +70,7 @@ export default function ChatMessage({
useEffect(() => { useEffect(() => {
// This effect is specifically for calling updateChat after streaming ends // This effect is specifically for calling updateChat after streaming ends
if (!isStreaming && streamUrl === null) { if (!isStreaming && streamUrl) {
if (updateChat) { if (updateChat) {
updateChat(chat, chatMessage, streamUrl); updateChat(chat, chatMessage, streamUrl);
} }

View file

@ -1,4 +1,4 @@
import _, { cloneDeep } from "lodash"; import _ from "lodash";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent"; import IconComponent from "../../components/genericIconComponent";
import { deleteFlowPool } from "../../controllers/API"; import { deleteFlowPool } from "../../controllers/API";
@ -11,30 +11,21 @@ import {
ChatOutputType, ChatOutputType,
FlowPoolObjectType, FlowPoolObjectType,
} from "../../types/chat"; } from "../../types/chat";
import { NodeType } from "../../types/flow";
import { validateNodes } from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils"; import { classNames } from "../../utils/utils";
import ChatInput from "./chatInput"; import ChatInput from "./chatInput";
import ChatMessage from "./chatMessage"; import ChatMessage from "./chatMessage";
export default function NewChatView(): JSX.Element { export default function NewChatView({
const [chatValue, setChatValue] = useState(""); sendMessage,
const { chatValue,
flowPool, setChatValue,
outputs, lockChat,
inputs, setLockChat,
getNode, }): JSX.Element {
setNode, const { flowPool, outputs, inputs, CleanFlowPool } = useFlowStore();
buildFlow, const { setNoticeData } = useAlertStore();
getFlow,
CleanFlowPool,
} = useFlowStore();
const { setErrorData, setNoticeData } = useAlertStore();
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const setIsBuilding = useFlowStore((state) => state.setIsBuilding);
const [lockChat, setLockChat] = useState(false);
const messagesRef = useRef<HTMLDivElement | null>(null); const messagesRef = useRef<HTMLDivElement | null>(null);
const isBuilding = useFlowStore((state) => state.isBuilding);
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]); const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const inputTypes = inputs.map((obj) => obj.type); const inputTypes = inputs.map((obj) => obj.type);
@ -115,40 +106,6 @@ export default function NewChatView(): JSX.Element {
} }
}, []); }, []);
async function sendMessage(count = 1): Promise<void> {
if (isBuilding) return;
const { nodes, edges } = getFlow();
let nodeValidationErrors = validateNodes(nodes, edges);
if (nodeValidationErrors.length === 0) {
setIsBuilding(true);
setLockChat(true);
setChatValue("");
const chatInputId = inputIds.find((inputId) =>
inputId.includes("ChatInput")
);
const chatInput: NodeType = getNode(chatInputId!) as NodeType;
if (chatInput) {
let newNode = cloneDeep(chatInput);
newNode.data.node!.template["message"].value = chatValue;
setNode(chatInputId!, newNode);
}
for (let i = 0; i < count; i++) {
await buildFlow().catch((err) => {
console.error(err);
setLockChat(false);
});
}
setLockChat(false);
//set chat message in the flow and run build
//@ts-ignore
} else {
setErrorData({
title: "Oops! Looks like you missed some required information:",
list: nodeValidationErrors,
});
}
}
function clearChat(): void { function clearChat(): void {
setChatHistory([]); setChatHistory([]);
deleteFlowPool(currentFlowId).then((_) => { deleteFlowPool(currentFlowId).then((_) => {

View file

@ -66,6 +66,7 @@ interface BaseModalProps {
| "small" | "small"
| "medium" | "medium"
| "large" | "large"
| "large-thin"
| "large-h-full" | "large-h-full"
| "small-h-full" | "small-h-full"
| "medium-h-full" | "medium-h-full"
@ -128,6 +129,10 @@ function BaseModal({
minWidth = "min-w-[80vw]"; minWidth = "min-w-[80vw]";
height = "h-[80vh]"; height = "h-[80vh]";
break; break;
case "large-thin":
minWidth = "min-w-[65vw]";
height = "h-[80vh]";
break;
case "large-h-full": case "large-h-full":
minWidth = "min-w-[80vw]"; minWidth = "min-w-[80vw]";
break; break;

View file

@ -576,6 +576,7 @@ export default function FormModal({
chatHistory.length - 1 === index ? true : false chatHistory.length - 1 === index ? true : false
} }
key={index} key={index}
updateChat={() => {}}
/> />
)) ))
) : ( ) : (

View file

@ -175,7 +175,7 @@
@apply fixed bottom-4 right-4; @apply fixed bottom-4 right-4;
} }
.message-button-icon { .message-button-icon {
@apply fill-chat-trigger stroke-chat-trigger stroke-1; @apply fill-medium-indigo stroke-medium-indigo stroke-1;
} }
.disabled-message-button-icon { .disabled-message-button-icon {
@apply fill-chat-trigger-disabled stroke-chat-trigger-disabled stroke-1; @apply fill-chat-trigger-disabled stroke-chat-trigger-disabled stroke-1;

View file

@ -524,11 +524,7 @@ export type chatMessagePropsType = {
chat: ChatMessageType; chat: ChatMessageType;
lockChat: boolean; lockChat: boolean;
lastMessage: boolean; lastMessage: boolean;
updateChat?: ( updateChat: (chat: ChatMessageType, message: string, stream_url: string) => void;
chat: ChatMessageType,
message: string,
stream_url: string | null
) => void;
}; };
export type formModalPropsType = { export type formModalPropsType = {