Merge remote-tracking branch 'origin/dev' into saveComponent
This commit is contained in:
commit
4f50425807
15 changed files with 195 additions and 75 deletions
|
|
@ -56,6 +56,14 @@ LANGFLOW_REMOVE_API_KEYS=
|
||||||
# LANGFLOW_REDIS_CACHE_EXPIRE (default: 3600)
|
# LANGFLOW_REDIS_CACHE_EXPIRE (default: 3600)
|
||||||
LANGFLOW_CACHE_TYPE=
|
LANGFLOW_CACHE_TYPE=
|
||||||
|
|
||||||
|
# Auto login
|
||||||
|
# If set to true then a superuser will be logged in automatically
|
||||||
|
# and the login page will be skipped, keeping the
|
||||||
|
# default experience of Langflow
|
||||||
|
# Values: true, false
|
||||||
|
# Example: LANGFLOW_AUTO_LOGIN=true
|
||||||
|
LANGFLOW_AUTO_LOGIN=
|
||||||
|
|
||||||
# Superuser username
|
# Superuser username
|
||||||
# Example: LANGFLOW_SUPERUSER=admin
|
# Example: LANGFLOW_SUPERUSER=admin
|
||||||
LANGFLOW_SUPERUSER=
|
LANGFLOW_SUPERUSER=
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ langfuse = "^1.0.13"
|
||||||
pillow = "^10.0.0"
|
pillow = "^10.0.0"
|
||||||
metal-sdk = "^2.2.0"
|
metal-sdk = "^2.2.0"
|
||||||
markupsafe = "^2.1.3"
|
markupsafe = "^2.1.3"
|
||||||
|
numexpr = "^2.8.6"
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
from langchain.llms import HuggingFaceEndpoint
|
from langchain.llms.huggingface_endpoint import HuggingFaceEndpoint
|
||||||
from langchain.llms.base import BaseLLM
|
from langchain.llms.base import BaseLLM
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,7 +13,6 @@ class HuggingFaceEndpointsComponent(CustomComponent):
|
||||||
"endpoint_url": {"display_name": "Endpoint URL", "password": True},
|
"endpoint_url": {"display_name": "Endpoint URL", "password": True},
|
||||||
"task": {
|
"task": {
|
||||||
"display_name": "Task",
|
"display_name": "Task",
|
||||||
"type": "select",
|
|
||||||
"options": ["text2text-generation", "text-generation", "summarization"],
|
"options": ["text2text-generation", "text-generation", "summarization"],
|
||||||
},
|
},
|
||||||
"huggingfacehub_api_token": {"display_name": "API token", "password": True},
|
"huggingfacehub_api_token": {"display_name": "API token", "password": True},
|
||||||
|
|
@ -27,7 +26,7 @@ class HuggingFaceEndpointsComponent(CustomComponent):
|
||||||
def build(
|
def build(
|
||||||
self,
|
self,
|
||||||
endpoint_url: str,
|
endpoint_url: str,
|
||||||
task="text2text-generation",
|
task: str = "text2text-generation",
|
||||||
huggingfacehub_api_token: Optional[str] = None,
|
huggingfacehub_api_token: Optional[str] = None,
|
||||||
model_kwargs: Optional[dict] = None,
|
model_kwargs: Optional[dict] = None,
|
||||||
) -> BaseLLM:
|
) -> BaseLLM:
|
||||||
|
|
@ -36,6 +35,7 @@ class HuggingFaceEndpointsComponent(CustomComponent):
|
||||||
endpoint_url=endpoint_url,
|
endpoint_url=endpoint_url,
|
||||||
task=task,
|
task=task,
|
||||||
huggingfacehub_api_token=huggingfacehub_api_token,
|
huggingfacehub_api_token=huggingfacehub_api_token,
|
||||||
|
model_kwargs=model_kwargs,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError("Could not connect to HuggingFace Endpoints API.") from e
|
raise ValueError("Could not connect to HuggingFace Endpoints API.") from e
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,53 @@
|
||||||
from .base import NestedDict
|
# LANGCHAIN_BASE_TYPES = {
|
||||||
|
# "Chain": Chain,
|
||||||
|
# "AgentExecutor": AgentExecutor,
|
||||||
|
# "Tool": Tool,
|
||||||
|
# "BaseLLM": BaseLLM,
|
||||||
|
# "PromptTemplate": PromptTemplate,
|
||||||
|
# "BaseLoader": BaseLoader,
|
||||||
|
# "Document": Document,
|
||||||
|
# "TextSplitter": TextSplitter,
|
||||||
|
# "VectorStore": VectorStore,
|
||||||
|
# "Embeddings": Embeddings,
|
||||||
|
# "BaseRetriever": BaseRetriever,
|
||||||
|
# "BaseOutputParser": BaseOutputParser,
|
||||||
|
# "BaseMemory": BaseMemory,
|
||||||
|
# "BaseChatMemory": BaseChatMemory,
|
||||||
|
# }
|
||||||
|
from .constants import (
|
||||||
|
Tool,
|
||||||
|
PromptTemplate,
|
||||||
|
Chain,
|
||||||
|
BaseChatMemory,
|
||||||
|
BaseLLM,
|
||||||
|
BaseLoader,
|
||||||
|
BaseMemory,
|
||||||
|
BaseOutputParser,
|
||||||
|
BaseRetriever,
|
||||||
|
VectorStore,
|
||||||
|
Embeddings,
|
||||||
|
TextSplitter,
|
||||||
|
Document,
|
||||||
|
AgentExecutor,
|
||||||
|
NestedDict,
|
||||||
|
Data,
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = ["NestedDict"]
|
__all__ = [
|
||||||
|
"NestedDict",
|
||||||
|
"Data",
|
||||||
|
"Tool",
|
||||||
|
"PromptTemplate",
|
||||||
|
"Chain",
|
||||||
|
"BaseChatMemory",
|
||||||
|
"BaseLLM",
|
||||||
|
"BaseLoader",
|
||||||
|
"BaseMemory",
|
||||||
|
"BaseOutputParser",
|
||||||
|
"BaseRetriever",
|
||||||
|
"VectorStore",
|
||||||
|
"Embeddings",
|
||||||
|
"TextSplitter",
|
||||||
|
"Document",
|
||||||
|
"AgentExecutor",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
from typing import Union, Dict
|
|
||||||
|
|
||||||
# Type alias for more complex dicts
|
|
||||||
NestedDict = Dict[str, Union[str, Dict]]
|
|
||||||
50
src/backend/langflow/field_typing/constants.py
Normal file
50
src/backend/langflow/field_typing/constants.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
from langchain.agents.agent import AgentExecutor
|
||||||
|
from langchain.chains.base import Chain
|
||||||
|
from langchain.document_loaders.base import BaseLoader
|
||||||
|
from langchain.llms.base import BaseLLM
|
||||||
|
from langchain.memory.chat_memory import BaseChatMemory
|
||||||
|
from langchain.prompts import PromptTemplate
|
||||||
|
from langchain.schema import BaseOutputParser, BaseRetriever, Document
|
||||||
|
from langchain.schema.embeddings import Embeddings
|
||||||
|
from langchain.schema.memory import BaseMemory
|
||||||
|
from langchain.text_splitter import TextSplitter
|
||||||
|
from langchain.tools import Tool
|
||||||
|
from langchain.vectorstores.base import VectorStore
|
||||||
|
from typing import Union, Dict
|
||||||
|
|
||||||
|
# Type alias for more complex dicts
|
||||||
|
NestedDict = Dict[str, Union[str, Dict]]
|
||||||
|
|
||||||
|
|
||||||
|
class Data:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
LANGCHAIN_BASE_TYPES = {
|
||||||
|
"Chain": Chain,
|
||||||
|
"AgentExecutor": AgentExecutor,
|
||||||
|
"Tool": Tool,
|
||||||
|
"BaseLLM": BaseLLM,
|
||||||
|
"PromptTemplate": PromptTemplate,
|
||||||
|
"BaseLoader": BaseLoader,
|
||||||
|
"Document": Document,
|
||||||
|
"TextSplitter": TextSplitter,
|
||||||
|
"VectorStore": VectorStore,
|
||||||
|
"Embeddings": Embeddings,
|
||||||
|
"BaseRetriever": BaseRetriever,
|
||||||
|
"BaseOutputParser": BaseOutputParser,
|
||||||
|
"BaseMemory": BaseMemory,
|
||||||
|
"BaseChatMemory": BaseChatMemory,
|
||||||
|
}
|
||||||
|
# Langchain base types plus Python base types
|
||||||
|
CUSTOM_COMPONENT_SUPPORTED_TYPES = {
|
||||||
|
**LANGCHAIN_BASE_TYPES,
|
||||||
|
"str": str,
|
||||||
|
"int": int,
|
||||||
|
"float": float,
|
||||||
|
"bool": bool,
|
||||||
|
"list": list,
|
||||||
|
"dict": dict,
|
||||||
|
"NestedDict": NestedDict,
|
||||||
|
"Data": Data,
|
||||||
|
}
|
||||||
|
|
@ -216,6 +216,16 @@ class Vertex:
|
||||||
}
|
}
|
||||||
elif isinstance(_value, dict):
|
elif isinstance(_value, dict):
|
||||||
params[key] = _value
|
params[key] = _value
|
||||||
|
elif value.get("type") == "int" and value.get("value") is not None:
|
||||||
|
try:
|
||||||
|
params[key] = int(value.get("value"))
|
||||||
|
except ValueError:
|
||||||
|
params[key] = value.get("value")
|
||||||
|
elif value.get("type") == "float" and value.get("value") is not None:
|
||||||
|
try:
|
||||||
|
params[key] = float(value.get("value"))
|
||||||
|
except ValueError:
|
||||||
|
params[key] = value.get("value")
|
||||||
else:
|
else:
|
||||||
params[key] = value.get("value")
|
params[key] = value.get("value")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,33 @@
|
||||||
from langchain.prompts import PromptTemplate
|
|
||||||
from langchain.chains.base import Chain
|
|
||||||
from langchain.document_loaders.base import BaseLoader
|
|
||||||
from langchain.schema.embeddings import Embeddings
|
|
||||||
from langchain.llms.base import BaseLLM
|
|
||||||
from langchain.schema import BaseRetriever, Document
|
|
||||||
from langchain.text_splitter import TextSplitter
|
|
||||||
from langchain.tools import Tool
|
|
||||||
from langchain.vectorstores.base import VectorStore
|
|
||||||
from langchain.schema import BaseOutputParser
|
|
||||||
from langchain.schema.memory import BaseMemory
|
|
||||||
from langchain.memory.chat_memory import BaseChatMemory
|
|
||||||
from langchain.agents.agent import AgentExecutor
|
|
||||||
|
|
||||||
LANGCHAIN_BASE_TYPES = {
|
|
||||||
"Chain": Chain,
|
|
||||||
"AgentExecutor": AgentExecutor,
|
|
||||||
"Tool": Tool,
|
|
||||||
"BaseLLM": BaseLLM,
|
|
||||||
"PromptTemplate": PromptTemplate,
|
|
||||||
"BaseLoader": BaseLoader,
|
|
||||||
"Document": Document,
|
|
||||||
"TextSplitter": TextSplitter,
|
|
||||||
"VectorStore": VectorStore,
|
|
||||||
"Embeddings": Embeddings,
|
|
||||||
"BaseRetriever": BaseRetriever,
|
|
||||||
"BaseOutputParser": BaseOutputParser,
|
|
||||||
"BaseMemory": BaseMemory,
|
|
||||||
"BaseChatMemory": BaseChatMemory,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Langchain base types plus Python base types
|
|
||||||
CUSTOM_COMPONENT_SUPPORTED_TYPES = {
|
|
||||||
**LANGCHAIN_BASE_TYPES,
|
|
||||||
"str": str,
|
|
||||||
"int": int,
|
|
||||||
"float": float,
|
|
||||||
"bool": bool,
|
|
||||||
"list": list,
|
|
||||||
"dict": dict,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CUSTOM_COMPONENT_CODE = """from langflow import CustomComponent
|
DEFAULT_CUSTOM_COMPONENT_CODE = """from langflow import CustomComponent
|
||||||
|
|
||||||
from langchain.llms.base import BaseLLM
|
from langflow.field_typing import (
|
||||||
from langchain.chains import LLMChain
|
Tool,
|
||||||
from langchain.prompts import PromptTemplate
|
PromptTemplate,
|
||||||
from langchain.schema import Document
|
Chain,
|
||||||
|
BaseChatMemory,
|
||||||
|
BaseLLM,
|
||||||
|
BaseLoader,
|
||||||
|
BaseMemory,
|
||||||
|
BaseOutputParser,
|
||||||
|
BaseRetriever,
|
||||||
|
VectorStore,
|
||||||
|
Embeddings,
|
||||||
|
TextSplitter,
|
||||||
|
Document,
|
||||||
|
AgentExecutor,
|
||||||
|
NestedDict,
|
||||||
|
Data,
|
||||||
|
)
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
class YourComponent(CustomComponent):
|
class Component(CustomComponent):
|
||||||
display_name: str = "Custom Component"
|
display_name: str = "Custom Component"
|
||||||
description: str = "Create any custom component you want!"
|
description: str = "Create any custom component you want!"
|
||||||
|
|
||||||
def build_config(self):
|
def build_config(self):
|
||||||
return { "url": { "multiline": True, "required": True } }
|
return {"param": {"display_name": "Parameter"}}
|
||||||
|
|
||||||
|
def build(self, param: Data) -> Data:
|
||||||
|
return param
|
||||||
|
|
||||||
def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:
|
|
||||||
response = requests.get(url)
|
|
||||||
chain = LLMChain(llm=llm, prompt=prompt)
|
|
||||||
result = chain.run(response.text[:300])
|
|
||||||
return Document(page_content=str(result))
|
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from typing import Any, Callable, List, Optional, Union
|
from typing import Any, Callable, List, Optional, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||||
from langflow.interface.custom.component import Component
|
from langflow.interface.custom.component import Component
|
||||||
from langflow.interface.custom.directory_reader import DirectoryReader
|
from langflow.interface.custom.directory_reader import DirectoryReader
|
||||||
from langflow.services.getters import get_db_service
|
from langflow.services.getters import get_db_service
|
||||||
|
|
@ -108,6 +108,9 @@ class CustomComponent(Component, extra=Extra.allow):
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
elif not arg.get("type"):
|
||||||
|
# Set the type to Data
|
||||||
|
arg["type"] = "Data"
|
||||||
return args
|
return args
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from typing import Any, List
|
||||||
from langflow.api.utils import get_new_key
|
from langflow.api.utils import get_new_key
|
||||||
from langflow.interface.agents.base import agent_creator
|
from langflow.interface.agents.base import agent_creator
|
||||||
from langflow.interface.chains.base import chain_creator
|
from langflow.interface.chains.base import chain_creator
|
||||||
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||||
from langflow.interface.custom.utils import extract_inner_type
|
from langflow.interface.custom.utils import extract_inner_type
|
||||||
from langflow.interface.document_loaders.base import documentloader_creator
|
from langflow.interface.document_loaders.base import documentloader_creator
|
||||||
from langflow.interface.embeddings.base import embedding_creator
|
from langflow.interface.embeddings.base import embedding_creator
|
||||||
|
|
@ -288,6 +288,24 @@ def add_base_classes(frontend_node, return_types: List[str]):
|
||||||
frontend_node.get("base_classes").append(base_class)
|
frontend_node.get("base_classes").append(base_class)
|
||||||
|
|
||||||
|
|
||||||
|
def add_output_types(frontend_node, return_types: List[str]):
|
||||||
|
"""Add output types to the frontend node"""
|
||||||
|
for return_type in return_types:
|
||||||
|
if return_type not in CUSTOM_COMPONENT_SUPPORTED_TYPES or return_type is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail={
|
||||||
|
"error": (
|
||||||
|
"Invalid return type should be one of: "
|
||||||
|
f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
|
||||||
|
),
|
||||||
|
"traceback": traceback.format_exc(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
frontend_node.get("output_types").append(return_type)
|
||||||
|
|
||||||
|
|
||||||
def build_langchain_template_custom_component(custom_component: CustomComponent):
|
def build_langchain_template_custom_component(custom_component: CustomComponent):
|
||||||
"""Build a custom component template for the langchain"""
|
"""Build a custom component template for the langchain"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -314,6 +332,9 @@ def build_langchain_template_custom_component(custom_component: CustomComponent)
|
||||||
add_base_classes(
|
add_base_classes(
|
||||||
frontend_node, custom_component.get_function_entrypoint_return_type
|
frontend_node, custom_component.get_function_entrypoint_return_type
|
||||||
)
|
)
|
||||||
|
add_output_types(
|
||||||
|
frontend_node, custom_component.get_function_entrypoint_return_type
|
||||||
|
)
|
||||||
logger.debug("Added base classes")
|
logger.debug("Added base classes")
|
||||||
return frontend_node
|
return frontend_node
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,9 @@ def get_langfuse_callback(trace_id):
|
||||||
if langfuse := LangfuseInstance.get():
|
if langfuse := LangfuseInstance.get():
|
||||||
logger.debug("Langfuse credentials found")
|
logger.debug("Langfuse credentials found")
|
||||||
try:
|
try:
|
||||||
trace = langfuse.trace(CreateTrace(id=trace_id))
|
trace = langfuse.trace(
|
||||||
|
CreateTrace(name="langflow-" + trace_id, id=trace_id)
|
||||||
|
)
|
||||||
return trace.getNewHandler()
|
return trace.getNewHandler()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.error(f"Error initializing langfuse callback: {exc}")
|
logger.error(f"Error initializing langfuse callback: {exc}")
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from langflow.template.field.base import TemplateField
|
||||||
from langflow.template.frontend_node.base import FrontendNode
|
from langflow.template.frontend_node.base import FrontendNode
|
||||||
from langflow.template.template.base import Template
|
from langflow.template.template.base import Template
|
||||||
from langflow.interface.custom.constants import DEFAULT_CUSTOM_COMPONENT_CODE
|
from langflow.interface.custom.constants import DEFAULT_CUSTOM_COMPONENT_CODE
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class CustomComponentFrontendNode(FrontendNode):
|
class CustomComponentFrontendNode(FrontendNode):
|
||||||
|
|
@ -24,7 +25,7 @@ class CustomComponentFrontendNode(FrontendNode):
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
description: str = "Create any custom component you want!"
|
description: Optional[str] = None
|
||||||
base_classes: list[str] = []
|
base_classes: list[str] = []
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,9 @@ def get_base_classes(cls):
|
||||||
"""Get the base classes of a class.
|
"""Get the base classes of a class.
|
||||||
These are used to determine the output of the nodes.
|
These are used to determine the output of the nodes.
|
||||||
"""
|
"""
|
||||||
if bases := cls.__bases__:
|
|
||||||
|
if hasattr(cls, "__bases__") and cls.__bases__:
|
||||||
|
bases = cls.__bases__
|
||||||
result = []
|
result = []
|
||||||
for base in bases:
|
for base in bases:
|
||||||
if any(type in base.__module__ for type in ["pydantic", "abc"]):
|
if any(type in base.__module__ for type in ["pydantic", "abc"]):
|
||||||
|
|
|
||||||
|
|
@ -260,9 +260,6 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
// simulate a click on the link element to trigger the download
|
// simulate a click on the link element to trigger the download
|
||||||
link.click();
|
link.click();
|
||||||
setNoticeData({
|
|
||||||
title: "Warning: Critical data, JSON file may include API keys.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadFlows() {
|
function downloadFlows() {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import IconComponent from "../../components/genericIconComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
import { Checkbox } from "../../components/ui/checkbox";
|
||||||
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { removeApiKeys } from "../../utils/reactflowUtils";
|
import { removeApiKeys } from "../../utils/reactflowUtils";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
|
|
@ -11,7 +12,8 @@ import BaseModal from "../baseModal";
|
||||||
const ExportModal = forwardRef(
|
const ExportModal = forwardRef(
|
||||||
(props: { children: ReactNode }, ref): JSX.Element => {
|
(props: { children: ReactNode }, ref): JSX.Element => {
|
||||||
const { flows, tabId, downloadFlow } = useContext(TabsContext);
|
const { flows, tabId, downloadFlow } = useContext(TabsContext);
|
||||||
const [checked, setChecked] = useState(false);
|
const { setNoticeData } = useContext(alertContext);
|
||||||
|
const [checked, setChecked] = useState(true);
|
||||||
const flow = flows.find((f) => f.id === tabId);
|
const flow = flows.find((f) => f.id === tabId);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setName(flow!.name);
|
setName(flow!.name);
|
||||||
|
|
@ -44,6 +46,7 @@ const ExportModal = forwardRef(
|
||||||
<div className="mt-3 flex items-center space-x-2">
|
<div className="mt-3 flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="terms"
|
id="terms"
|
||||||
|
checked={checked}
|
||||||
onCheckedChange={(event: boolean) => {
|
onCheckedChange={(event: boolean) => {
|
||||||
setChecked(event);
|
setChecked(event);
|
||||||
}}
|
}}
|
||||||
|
|
@ -52,18 +55,26 @@ const ExportModal = forwardRef(
|
||||||
Save with my API keys
|
Save with my API keys
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="text-xs text-destructive">
|
||||||
|
Caution: Uncheck this box only removes API keys from fields
|
||||||
|
specifically designated for API keys.
|
||||||
|
</span>
|
||||||
</BaseModal.Content>
|
</BaseModal.Content>
|
||||||
|
|
||||||
<BaseModal.Footer>
|
<BaseModal.Footer>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (checked)
|
if (checked) {
|
||||||
downloadFlow(
|
downloadFlow(
|
||||||
flows.find((flow) => flow.id === tabId)!,
|
flows.find((flow) => flow.id === tabId)!,
|
||||||
name!,
|
name!,
|
||||||
description
|
description
|
||||||
);
|
);
|
||||||
else
|
setNoticeData({
|
||||||
|
title:
|
||||||
|
"Warning: Critical data, JSON file may include API keys.",
|
||||||
|
});
|
||||||
|
} else
|
||||||
downloadFlow(
|
downloadFlow(
|
||||||
removeApiKeys(flows.find((flow) => flow.id === tabId)!),
|
removeApiKeys(flows.find((flow) => flow.id === tabId)!),
|
||||||
name!,
|
name!,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue