Merge zustand/io/migration into zustand/io/migration

This commit is contained in:
igorrCarvalho 2024-02-26 16:14:13 -03:00
commit 82f29cfcb6
19 changed files with 367 additions and 376 deletions

View file

@ -1,7 +1,6 @@
from typing import Optional
from langchain.chains import RetrievalQAWithSourcesChain
from langchain.chains.combine_documents.base import BaseCombineDocumentsChain
from langchain_core.documents import Document
from langflow import CustomComponent
@ -18,6 +17,7 @@ class RetrievalQAWithSourcesChainComponent(CustomComponent):
"chain_type": {
"display_name": "Chain Type",
"options": ["stuff", "map_reduce", "map_rerank", "refine"],
"info": "The type of chain to use to combined Documents.",
},
"memory": {"display_name": "Memory"},
"return_source_documents": {"display_name": "Return Source Documents"},
@ -27,7 +27,6 @@ class RetrievalQAWithSourcesChainComponent(CustomComponent):
self,
retriever: BaseRetriever,
llm: BaseLanguageModel,
combine_documents_chain: BaseCombineDocumentsChain,
chain_type: str,
memory: Optional[BaseMemory] = None,
return_source_documents: Optional[bool] = True,
@ -35,7 +34,6 @@ class RetrievalQAWithSourcesChainComponent(CustomComponent):
runnable = RetrievalQAWithSourcesChain.from_chain_type(
llm=llm,
chain_type=chain_type,
combine_documents_chain=combine_documents_chain,
memory=memory,
return_source_documents=return_source_documents,
retriever=retriever,

View file

@ -341,7 +341,10 @@ class Vertex:
elif value.get("type") == "str" and val is not None:
# val may contain escaped \n, \t, etc.
# so we need to unescape it
params[key] = val.encode().decode("unicode_escape")
if isinstance(val, list):
params[key] = [v.encode().decode("unicode_escape") for v in val]
elif isinstance(val, str):
params[key] = val.encode().decode("unicode_escape")
elif val is not None and val != "":
params[key] = val

View file

@ -4,7 +4,7 @@ from langchain_community.utilities import requests
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_class
class WrapperCreator(LangChainTypeCreator):
@ -20,14 +20,6 @@ class WrapperCreator(LangChainTypeCreator):
def get_signature(self, name: str) -> Optional[Dict]:
try:
if name in self.from_method_nodes:
return build_template_from_method(
name,
type_to_cls_dict=self.type_to_loader_dict,
add_function=True,
method_name=self.from_method_nodes[name],
)
return build_template_from_class(name, self.type_to_loader_dict)
except ValueError as exc:
raise ValueError("Wrapper not found") from exc

View file

@ -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]);

View file

@ -135,7 +135,6 @@ export default function GenericNode({
const iconClassName = `generic-node-icon ${
!showNode ? "absolute inset-x-6 h-12 w-12" : ""
}`;
if (iconElement && isEmoji) {
return nodeIconFragment(iconElement);
} else {
@ -168,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";
@ -193,7 +193,6 @@ export default function GenericNode({
};
const renderIconPlayOrPauseComponents = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
if (buildStatus === BuildStatus.BUILDING) {
return <Loading />;
@ -201,7 +200,7 @@ export default function GenericNode({
return (
<IconComponent
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 +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);
}}
>
<div>
<ShadTooltip
styleClasses="cursor-default"
content={
buildStatus === BuildStatus.BUILDING ? (
<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>
)
"Build"
}
side="bottom"
>
<div className="generic-node-status-position flex items-center justify-center">
{renderIconPlayOrPauseComponents(
buildStatus,
validationStatus
)}
</div>
</ShadTooltip>
@ -514,7 +490,6 @@ export default function GenericNode({
)}
<div className="">
<ShadTooltip
styleClasses="cursor-default"
content={
data?.buildStatus === BuildStatus.BUILDING ? (
<span>Building...</span>
@ -530,7 +505,6 @@ export default function GenericNode({
</div>
)
}
side="bottom"
>
<div>
{renderIconStatusComponents(

View file

@ -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<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(() => {
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 (
<BaseModal
size={haveChat ? "large" : "small"}
size={haveChat ? (selectedTab === 0 ? "large-thin" : "large") : "small"}
open={open}
setOpen={setOpen}
>
@ -60,178 +106,196 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
</div>
</BaseModal.Header>
<BaseModal.Content>
<div className="flex-max-width mt-2 h-[80vh]">
{selectedTab !== 0 && (
<div
className={cn(
"mr-6 flex h-full w-2/6 flex-shrink-0 flex-col justify-start overflow-auto scrollbar-hide",
haveChat ? "w-2/6" : "w-full"
)}
>
<Tabs
value={selectedTab.toString()}
className={"api-modal-tabs "}
onValueChange={(value) => {
setSelectedTab(Number(value));
}}
<div className="flex h-full flex-col">
<div className="flex-max-width mt-2 h-full">
{selectedTab !== 0 && (
<div
className={cn(
"mr-6 flex h-full w-2/6 flex-shrink-0 flex-col justify-start overflow-auto scrollbar-hide",
haveChat ? "w-2/6" : "w-full"
)}
>
<div className="api-modal-tablist-div">
<TabsList>
{inputs.length > 0 && (
<TabsTrigger value={"1"}>Inputs</TabsTrigger>
)}
{outputs.length > 0 && (
<TabsTrigger value={"2"}>Outputs</TabsTrigger>
)}
</TabsList>
</div>
<TabsContent
value={"1"}
className="api-modal-tabs-content mt-4"
<Tabs
value={selectedTab.toString()}
className={
"flex h-full flex-col overflow-hidden rounded-md border bg-muted text-center"
}
onValueChange={(value) => {
setSelectedTab(Number(value));
}}
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Type"} />
Text Inputs
<div className="api-modal-tablist-div">
<TabsList>
{inputs.length > 0 && (
<TabsTrigger value={"1"}>Inputs</TabsTrigger>
)}
{outputs.length > 0 && (
<TabsTrigger value={"2"}>Outputs</TabsTrigger>
)}
</TabsList>
</div>
{nodes
.filter((node) =>
inputs.some((input) => input.id === node.id)
)
.map((node, index) => {
const input = inputs.find(
(input) => input.id === node.id
)!;
return (
<div
className="file-component-accordion-div"
key={index}
>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{input.id}
</Badge>
{haveChat && (
<div
className="-mb-1 pr-4"
onClick={(event) => {
event.stopPropagation();
setSelectedViewField(input);
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div>
)}
</div>
}
key={index}
keyValue={input.id}
>
<div className="file-component-tab-column">
<div className="">
{input && (
<IOInputField
inputType={input.type}
inputId={input.id}
/>
)}
</div>
</div>
</AccordionComponent>
</div>
);
})}
</TabsContent>
<TabsContent
value={"2"}
className="api-modal-tabs-content mt-4"
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Braces"} />
Prompt Outputs
</div>
{nodes
.filter((node) =>
outputs.some((output) => output.id === node.id)
)
.map((node, index) => {
const output = outputs.find(
(output) => output.id === node.id
)!;
return (
<div
className="file-component-accordion-div"
key={index}
>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{output.id}
</Badge>
{haveChat && (
<div
className="-mb-1 pr-4"
onClick={(event) => {
event.stopPropagation();
setSelectedViewField(output);
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div>
)}
</div>
}
key={index}
keyValue={output.id}
>
<div className="file-component-tab-column">
<div className="">
{output && (
<IOOutputView
outputType={output.type}
outputId={output.id}
/>
)}
</div>
</div>
</AccordionComponent>
</div>
);
})}
</TabsContent>
</Tabs>
</div>
)}
{haveChat ? (
selectedViewField ? (
inputs.some((input) => input.id === selectedViewField.id) ? (
<IOInputField
inputType={selectedViewField.type!}
inputId={selectedViewField.id!}
/>
<TabsContent
value={"1"}
className="api-modal-tabs-content mt-4"
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Type"} />
Text Inputs
</div>
{nodes
.filter((node) =>
inputs.some((input) => input.id === node.id)
)
.map((node, index) => {
const input = inputs.find(
(input) => input.id === node.id
)!;
return (
<div
className="file-component-accordion-div"
key={index}
>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{input.id}
</Badge>
{haveChat && (
<div
className="-mb-1 pr-4"
onClick={(event) => {
event.stopPropagation();
setSelectedViewField(input);
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div>
)}
</div>
}
key={index}
keyValue={input.id}
>
<div className="file-component-tab-column">
<div className="">
{input && (
<IOInputField
inputType={input.type}
inputId={input.id}
/>
)}
</div>
</div>
</AccordionComponent>
</div>
);
})}
</TabsContent>
<TabsContent
value={"2"}
className="api-modal-tabs-content mt-4"
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Braces"} />
Prompt Outputs
</div>
{nodes
.filter((node) =>
outputs.some((output) => output.id === node.id)
)
.map((node, index) => {
const output = outputs.find(
(output) => output.id === node.id
)!;
return (
<div
className="file-component-accordion-div"
key={index}
>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{output.id}
</Badge>
{haveChat && (
<div
className="-mb-1 pr-4"
onClick={(event) => {
event.stopPropagation();
setSelectedViewField(output);
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div>
)}
</div>
}
key={index}
keyValue={output.id}
>
<div className="file-component-tab-column">
<div className="">
{output && (
<IOOutputView
outputType={output.type}
outputId={output.id}
/>
)}
</div>
</div>
</AccordionComponent>
</div>
);
})}
</TabsContent>
</Tabs>
</div>
)}
{haveChat ? (
selectedViewField ? (
inputs.some((input) => input.id === selectedViewField.id) ? (
<IOInputField
inputType={selectedViewField.type!}
inputId={selectedViewField.id!}
/>
) : (
<IOOutputView
outputType={selectedViewField.type!}
outputId={selectedViewField.id!}
/>
)
) : (
<IOOutputView
outputType={selectedViewField.type!}
outputId={selectedViewField.id!}
<NewChatView
sendMessage={sendMessage}
chatValue={chatValue}
setChatValue={setChatValue}
lockChat={lockChat}
setLockChat={setLockChat}
/>
)
) : (
<NewChatView />
)
) : (
<div className="absolute bottom-8 right-8">
<Button className="px-3">
<IconComponent name="Play" className="h-6 w-6" />
<div className="absolute bottom-8 right-8"></div>
)}
</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>
</div>
)}

View file

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

View file

@ -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);
}

View file

@ -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,31 +11,22 @@ 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";
import { INFO_MISSING_ALERT, NOCHATOUTPUT_NOTICE_ALERT } from "../../alerts_constants";
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<HTMLDivElement | null>(null);
const isBuilding = useFlowStore((state) => state.isBuilding);
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const inputTypes = inputs.map((obj) => obj.type);
@ -116,40 +107,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: INFO_MISSING_ALERT,
list: nodeValidationErrors,
});
}
}
function clearChat(): void {
setChatHistory([]);
deleteFlowPool(currentFlowId).then((_) => {

View file

@ -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;

View file

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

View file

@ -26,6 +26,7 @@ import {
updateFlowPosition,
} from "../../../../utils/reactflowUtils";
import { classNames, cn } from "../../../../utils/utils";
import { useUpdateNodeInternals } from "reactflow";
export default function NodeToolbarComponent({
data,
@ -86,6 +87,8 @@ export default function NodeToolbarComponent({
onCloseAdvancedModal!(false);
}
}, [showModalAdvanced]);
const updateNodeInternals = useUpdateNodeInternals();
useEffect(() => {
setFlowComponent(createFlowComponent(cloneDeep(data), version));
@ -191,6 +194,7 @@ export default function NodeToolbarComponent({
return newNode;
});
updateNodeInternals(data.id);
};
const [openModal, setOpenModal] = useState(false);

View file

@ -40,8 +40,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);
@ -49,6 +47,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();
@ -64,10 +65,6 @@ export default function StorePage(): JSX.Element {
const [searchNow, setSearchNow] = useState("");
const [selectFilter, setSelectFilter] = useState("all");
useEffect(() => {
handleGetTags();
}, []);
useEffect(() => {
if (!loadingApiKey) {
if (!hasApiKey) {
@ -87,9 +84,10 @@ export default function StorePage(): JSX.Element {
});
}
}
}, [loadingApiKey, validApiKey, hasApiKey]);
}, [loadingApiKey, validApiKey, hasApiKey, currentFlowId]);
useEffect(() => {
handleGetTags();
handleGetComponents();
}, [
tabActive,
@ -120,7 +118,7 @@ export default function StorePage(): JSX.Element {
}
function handleGetComponents() {
if (!hasApiKey || loadingApiKey) return;
if (loadingApiKey) return;
setLoading(true);
getStoreComponents({
component_id: id,
@ -177,23 +175,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 (
<PageLayout
betaIcon

View file

@ -1,19 +1,34 @@
import { create } from "zustand";
import { checkHasStore } from "../controllers/API";
import { checkHasApiKey, checkHasStore } from "../controllers/API";
import { StoreStoreType } from "../types/zustand/store";
import useAlertStore from "./alertStore";
export const useStoreStore = create<StoreStoreType>((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 });
});

View file

@ -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;
@ -276,7 +276,7 @@
@apply h-10 w-10 rounded p-1;
}
.generic-node-tooltip-div {
@apply ml-2 truncate;
@apply ml-2 max-w-[220px] truncate;
}
.generic-node-validation-div {
@apply max-h-96 overflow-auto;

View file

@ -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 = {

View file

@ -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<void>;
};