diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 91c455d1c..406c66fd5 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -20,6 +20,7 @@ import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; import { useTypesStore } from "./stores/typesStore"; +import { useStoreStore } from "./stores/storeStore"; export default function App() { const removeFromTempNotificationList = useAlertStore( @@ -28,7 +29,6 @@ export default function App() { const tempNotificationList = useAlertStore( (state) => state.tempNotificationList ); - const loading = useAlertStore((state) => state.loading); const [fetchError, setFetchError] = useState(false); const isLoading = useFlowsManagerStore((state) => state.isLoading); @@ -38,9 +38,11 @@ export default function App() { const { isAuthenticated } = useContext(AuthContext); const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows); + const fetchApiData = useStoreStore((state) => state.fetchApiData); const getTypes = useTypesStore((state) => state.getTypes); const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshStars = useDarkStore((state) => state.refreshStars); + const checkHasStore = useStoreStore((state) => state.checkHasStore); useEffect(() => { refreshStars(); @@ -52,6 +54,8 @@ export default function App() { getTypes().then(() => { refreshFlows(); }); + checkHasStore(); + fetchApiData(); } }, [isAuthenticated]); diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index a0dfebcd4..22f2a9b28 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -167,6 +167,7 @@ export default function GenericNode({ buildStatus: BuildStatus | undefined, validationStatus: validationStatusType | null ) => { + console.log(buildStatus); const isValid = validationStatus && validationStatus.valid; if (isValid) { return "green-status"; @@ -192,7 +193,6 @@ export default function GenericNode({ }; const renderIconPlayOrPauseComponents = ( buildStatus: BuildStatus | undefined, - validationStatus: validationStatusType | null ) => { if (buildStatus === BuildStatus.BUILDING) { return ; @@ -200,7 +200,7 @@ export default function GenericNode({ return ( ); } @@ -467,44 +467,21 @@ export default function GenericNode({ variant="secondary" className={"group h-9 px-1.5"} onClick={() => { - if (buildStatus === BuildStatus.BUILDING || isBuilding) + if (data?.buildStatus === BuildStatus.BUILDING || isBuilding) return; buildFlow(data.id); }} >
Building... - ) : !validationStatus ? ( - - Build{" "} - {" "} - flow to validate status. - - ) : ( -
- {typeof validationStatus.params === "string" - ? `${durationString}\n${validationStatus.params}` - .split("\n") - .map((line, index) => ( -
{line}
- )) - : durationString} -
- ) + "Build" } side="bottom" >
{renderIconPlayOrPauseComponents( buildStatus, - validationStatus )}
@@ -513,7 +490,6 @@ export default function GenericNode({ )}
Building... @@ -529,7 +505,6 @@ export default function GenericNode({
) } - side="bottom" >
{renderIconStatusComponents( diff --git a/src/frontend/src/components/IOview/index.tsx b/src/frontend/src/components/IOview/index.tsx index 9fc109e21..735f543d2 100644 --- a/src/frontend/src/components/IOview/index.tsx +++ b/src/frontend/src/components/IOview/index.tsx @@ -1,7 +1,11 @@ +import { cloneDeep } from "lodash"; import { useEffect, useState } from "react"; import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants"; import BaseModal from "../../modals/baseModal"; +import useAlertStore from "../../stores/alertStore"; import useFlowStore from "../../stores/flowStore"; +import { NodeType } from "../../types/flow"; +import { validateNodes } from "../../utils/reactflowUtils"; import { cn } from "../../utils/utils"; import AccordionComponent from "../AccordionComponent"; import IOInputField from "../IOInputField"; @@ -16,19 +20,22 @@ export default function IOView({ children, open, setOpen }): JSX.Element { const inputs = useFlowStore((state) => state.inputs).filter( (input) => input.type !== "ChatInput" ); + const chatInput = useFlowStore((state) => state.inputs).find( + (input) => input.type === "ChatInput" + ); const outputs = useFlowStore((state) => state.outputs).filter( (output) => output.type !== "ChatOutput" ); + const chatOutput = useFlowStore((state) => state.outputs).find( + (output) => output.type === "ChatOutput" + ); const nodes = useFlowStore((state) => state.nodes).filter( (node) => (inputs.some((input) => input.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" + outputs.some((output) => output.id === node.id)) ); + const haveChat = + chatInput || chatOutput const [selectedTab, setSelectedTab] = useState( 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 >(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 { + 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(() => { setSelectedViewField(undefined); setSelectedTab(inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0); @@ -43,7 +89,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element { return ( @@ -60,178 +106,196 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
-
- {selectedTab !== 0 && ( -
- { - setSelectedTab(Number(value)); - }} +
+
+ {selectedTab !== 0 && ( +
-
- - {inputs.length > 0 && ( - Inputs - )} - {outputs.length > 0 && ( - Outputs - )} - -
- - { + setSelectedTab(Number(value)); + }} > -
- - Text Inputs +
+ + {inputs.length > 0 && ( + Inputs + )} + {outputs.length > 0 && ( + Outputs + )} +
- {nodes - .filter((node) => - inputs.some((input) => input.id === node.id) - ) - .map((node, index) => { - const input = inputs.find( - (input) => input.id === node.id - )!; - return ( -
- - - {input.id} - - {haveChat && ( -
{ - event.stopPropagation(); - setSelectedViewField(input); - }} - > - -
- )} -
- } - key={index} - keyValue={input.id} - > -
-
- {input && ( - - )} -
-
- -
- ); - })} -
- -
- - Prompt Outputs -
- {nodes - .filter((node) => - outputs.some((output) => output.id === node.id) - ) - .map((node, index) => { - const output = outputs.find( - (output) => output.id === node.id - )!; - return ( -
- - - {output.id} - - {haveChat && ( -
{ - event.stopPropagation(); - setSelectedViewField(output); - }} - > - -
- )} -
- } - key={index} - keyValue={output.id} - > -
-
- {output && ( - - )} -
-
- -
- ); - })} - - -
- )} - {haveChat ? ( - selectedViewField ? ( - inputs.some((input) => input.id === selectedViewField.id) ? ( - + +
+ + Text Inputs +
+ {nodes + .filter((node) => + inputs.some((input) => input.id === node.id) + ) + .map((node, index) => { + const input = inputs.find( + (input) => input.id === node.id + )!; + return ( +
+ + + {input.id} + + {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(input); + }} + > + +
+ )} +
+ } + key={index} + keyValue={input.id} + > +
+
+ {input && ( + + )} +
+
+ +
+ ); + })} + + +
+ + Prompt Outputs +
+ {nodes + .filter((node) => + outputs.some((output) => output.id === node.id) + ) + .map((node, index) => { + const output = outputs.find( + (output) => output.id === node.id + )!; + return ( +
+ + + {output.id} + + {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(output); + }} + > + +
+ )} +
+ } + key={index} + keyValue={output.id} + > +
+
+ {output && ( + + )} +
+
+ +
+ ); + })} + + +
+ )} + + {haveChat ? ( + selectedViewField ? ( + inputs.some((input) => input.id === selectedViewField.id) ? ( + + ) : ( + + ) ) : ( - ) ) : ( - - ) - ) : ( -
-
+ {!haveChat && ( +
+
)} diff --git a/src/frontend/src/components/ViewTriggers/chat/index.tsx b/src/frontend/src/components/ViewTriggers/chat/index.tsx index f61da2969..9610f22ff 100644 --- a/src/frontend/src/components/ViewTriggers/chat/index.tsx +++ b/src/frontend/src/components/ViewTriggers/chat/index.tsx @@ -21,7 +21,7 @@ export default function ChatTrigger({}): JSX.Element { >
diff --git a/src/frontend/src/components/newChatView/chatMessage/index.tsx b/src/frontend/src/components/newChatView/chatMessage/index.tsx index 36fb3955e..31f4f0345 100644 --- a/src/frontend/src/components/newChatView/chatMessage/index.tsx +++ b/src/frontend/src/components/newChatView/chatMessage/index.tsx @@ -70,7 +70,7 @@ export default function ChatMessage({ useEffect(() => { // This effect is specifically for calling updateChat after streaming ends - if (!isStreaming && streamUrl === null) { + if (!isStreaming && streamUrl) { if (updateChat) { updateChat(chat, chatMessage, streamUrl); } diff --git a/src/frontend/src/components/newChatView/index.tsx b/src/frontend/src/components/newChatView/index.tsx index d069ea97c..38a633444 100644 --- a/src/frontend/src/components/newChatView/index.tsx +++ b/src/frontend/src/components/newChatView/index.tsx @@ -1,4 +1,4 @@ -import _, { cloneDeep } from "lodash"; +import _ from "lodash"; import { useEffect, useRef, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; import { deleteFlowPool } from "../../controllers/API"; @@ -11,30 +11,21 @@ import { ChatOutputType, FlowPoolObjectType, } from "../../types/chat"; -import { NodeType } from "../../types/flow"; -import { validateNodes } from "../../utils/reactflowUtils"; import { classNames } from "../../utils/utils"; import ChatInput from "./chatInput"; import ChatMessage from "./chatMessage"; -export default function NewChatView(): JSX.Element { - const [chatValue, setChatValue] = useState(""); - const { - flowPool, - outputs, - inputs, - getNode, - setNode, - buildFlow, - getFlow, - CleanFlowPool, - } = useFlowStore(); - const { setErrorData, setNoticeData } = useAlertStore(); +export default function NewChatView({ + sendMessage, + chatValue, + setChatValue, + lockChat, + setLockChat, +}): JSX.Element { + const { flowPool, outputs, inputs, CleanFlowPool } = useFlowStore(); + const { setNoticeData } = useAlertStore(); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); - const setIsBuilding = useFlowStore((state) => state.setIsBuilding); - const [lockChat, setLockChat] = useState(false); const messagesRef = useRef(null); - const isBuilding = useFlowStore((state) => state.isBuilding); const [chatHistory, setChatHistory] = useState([]); const inputTypes = inputs.map((obj) => obj.type); @@ -115,40 +106,6 @@ export default function NewChatView(): JSX.Element { } }, []); - async function sendMessage(count = 1): Promise { - 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 { setChatHistory([]); deleteFlowPool(currentFlowId).then((_) => { diff --git a/src/frontend/src/modals/baseModal/index.tsx b/src/frontend/src/modals/baseModal/index.tsx index 860551be9..134093f5c 100644 --- a/src/frontend/src/modals/baseModal/index.tsx +++ b/src/frontend/src/modals/baseModal/index.tsx @@ -66,6 +66,7 @@ interface BaseModalProps { | "small" | "medium" | "large" + | "large-thin" | "large-h-full" | "small-h-full" | "medium-h-full" @@ -128,6 +129,10 @@ function BaseModal({ minWidth = "min-w-[80vw]"; height = "h-[80vh]"; break; + case "large-thin": + minWidth = "min-w-[65vw]"; + height = "h-[80vh]"; + break; case "large-h-full": minWidth = "min-w-[80vw]"; break; diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index dfaf871ed..af6e9eace 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -576,6 +576,7 @@ export default function FormModal({ chatHistory.length - 1 === index ? true : false } key={index} + updateChat={() => {}} /> )) ) : ( diff --git a/src/frontend/src/pages/StorePage/index.tsx b/src/frontend/src/pages/StorePage/index.tsx index 8321be91d..8eeafc28f 100644 --- a/src/frontend/src/pages/StorePage/index.tsx +++ b/src/frontend/src/pages/StorePage/index.tsx @@ -39,8 +39,6 @@ export default function StorePage(): JSX.Element { const loadingApiKey = useStoreStore((state) => state.loadingApiKey); const setValidApiKey = useStoreStore((state) => state.updateValidApiKey); - const setLoadingApiKey = useStoreStore((state) => state.updateLoadingApiKey); - const setHasApiKey = useStoreStore((state) => state.updateHasApiKey); const { apiKey } = useContext(AuthContext); @@ -48,6 +46,9 @@ export default function StorePage(): JSX.Element { const setCurrentFlowId = useFlowsManagerStore( (state) => state.setCurrentFlowId ); + const currentFlowId = useFlowsManagerStore( + (state) => state.currentFlowId + ); const [loading, setLoading] = useState(true); const [loadingTags, setLoadingTags] = useState(true); const { id } = useParams(); @@ -63,10 +64,6 @@ export default function StorePage(): JSX.Element { const [searchNow, setSearchNow] = useState(""); const [selectFilter, setSelectFilter] = useState("all"); - useEffect(() => { - handleGetTags(); - }, []); - useEffect(() => { if (!loadingApiKey) { if (!hasApiKey) { @@ -86,9 +83,10 @@ export default function StorePage(): JSX.Element { }); } } - }, [loadingApiKey, validApiKey, hasApiKey]); + }, [loadingApiKey, validApiKey, hasApiKey, currentFlowId]); useEffect(() => { + handleGetTags(); handleGetComponents(); }, [ tabActive, @@ -119,7 +117,7 @@ export default function StorePage(): JSX.Element { } function handleGetComponents() { - if (!hasApiKey || loadingApiKey) return; + if (loadingApiKey) return; setLoading(true); getStoreComponents({ component_id: id, @@ -176,23 +174,6 @@ export default function StorePage(): JSX.Element { setPageSize(12); } - const fetchApiData = async () => { - setLoadingApiKey(true); - try { - const res = await checkHasApiKey(); - setHasApiKey(res?.has_api_key ?? false); - setValidApiKey(res?.is_valid ?? false); - setLoadingApiKey(false); - } catch (e) { - setLoadingApiKey(false); - console.log(e); - } - }; - - useEffect(() => { - fetchApiData(); - }, [apiKey]); - return ( ((set) => ({ hasStore: true, validApiKey: false, hasApiKey: false, loadingApiKey: true, - updateHasStore: (hasStore) => set(() => ({ hasStore: hasStore })), + checkHasStore: () => { + checkHasStore().then((res) => { + set({ hasStore: res?.enabled ?? false }); + }); + }, updateValidApiKey: (validApiKey) => set(() => ({ validApiKey: validApiKey })), updateLoadingApiKey: (loadingApiKey) => set(() => ({ loadingApiKey: loadingApiKey })), updateHasApiKey: (hasApiKey) => set(() => ({ hasApiKey: hasApiKey })), + fetchApiData: async () => { + set({ loadingApiKey: true }); + try { + const res = await checkHasApiKey(); + set({ + validApiKey: res?.is_valid ?? false, + hasApiKey: res?.has_api_key ?? false, + loadingApiKey: false, + }); + } catch (e) { + set({ loadingApiKey: false }); + console.log(e); + } + }, })); - -checkHasStore().then((res) => { - useStoreStore.setState({ hasStore: res?.enabled ?? false }); -}); diff --git a/src/frontend/src/style/applies.css b/src/frontend/src/style/applies.css index 9208c4b17..794032875 100644 --- a/src/frontend/src/style/applies.css +++ b/src/frontend/src/style/applies.css @@ -175,7 +175,7 @@ @apply fixed bottom-4 right-4; } .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 { @apply fill-chat-trigger-disabled stroke-chat-trigger-disabled stroke-1; diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 0a0da32ad..bc8582118 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -524,11 +524,7 @@ export type chatMessagePropsType = { chat: ChatMessageType; lockChat: boolean; lastMessage: boolean; - updateChat?: ( - chat: ChatMessageType, - message: string, - stream_url: string | null - ) => void; + updateChat: (chat: ChatMessageType, message: string, stream_url: string) => void; }; export type formModalPropsType = { diff --git a/src/frontend/src/types/zustand/store/index.ts b/src/frontend/src/types/zustand/store/index.ts index 0254c857d..34bf38ad1 100644 --- a/src/frontend/src/types/zustand/store/index.ts +++ b/src/frontend/src/types/zustand/store/index.ts @@ -3,8 +3,9 @@ export type StoreStoreType = { validApiKey: boolean; hasApiKey: boolean; loadingApiKey: boolean; - updateHasStore: (hasStore: boolean) => void; + checkHasStore: () => void; updateValidApiKey: (validApiKey: boolean) => void; updateHasApiKey: (hasApiKey: boolean) => void; updateLoadingApiKey: (loadingApiKey: boolean) => void; + fetchApiData: () => Promise; }; diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 2ca790c7b..c89786ce7 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -58,11 +58,12 @@ export function normalCaseToSnakeCase(str: string): string { .join("_"); } -export function toTitleCase(str: string | undefined): string { +export function toTitleCase(str: string | undefined, isNodeField?: boolean): string { if (!str) return ""; let result = str .split("_") .map((word, index) => { + if (isNodeField) return word if (index === 0) { return checkUpperWords( word[0].toUpperCase() + word.slice(1).toLowerCase() @@ -75,6 +76,7 @@ export function toTitleCase(str: string | undefined): string { return result .split("-") .map((word, index) => { + if (isNodeField) return word if (index === 0) { return checkUpperWords( word[0].toUpperCase() + word.slice(1).toLowerCase() @@ -642,6 +644,6 @@ export function getFieldTitle( return template[templateField].display_name ? template[templateField].display_name! : template[templateField].name - ? toTitleCase(template[templateField].name!) - : toTitleCase(templateField); + ? toTitleCase(template[templateField].name!, true) + : toTitleCase(templateField, true); }