merge fix

This commit is contained in:
cristhianzl 2024-06-06 14:23:01 -03:00
commit 686a07faaa
156 changed files with 1698 additions and 1641 deletions

View file

@ -36,7 +36,6 @@
# 📝 Conteúdo # 📝 Conteúdo
- [](#)
- [📝 Conteúdo](#-conteúdo) - [📝 Conteúdo](#-conteúdo)
- [📦 Introdução](#-introdução) - [📦 Introdução](#-introdução)
- [🎨 Criar Fluxos](#-criar-fluxos) - [🎨 Criar Fluxos](#-criar-fluxos)

View file

@ -27,6 +27,7 @@
<div align="center"> <div align="center">
<a href="./README.md"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a> <a href="./README.md"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a>
<a href="./README.PT.md"><img alt="README in Portuguese" src="https://img.shields.io/badge/Portuguese-d9d9d9"></a>
<a href="./README.zh_CN.md"><img alt="README in Simplified Chinese" src="https://img.shields.io/badge/简体中文-d9d9d9"></a> <a href="./README.zh_CN.md"><img alt="README in Simplified Chinese" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
</div> </div>

44
poetry.lock generated
View file

@ -4058,19 +4058,19 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"]
[[package]] [[package]]
name = "langchain-anthropic" name = "langchain-anthropic"
version = "0.1.15" version = "0.1.13"
description = "An integration package connecting AnthropicMessages and LangChain" description = "An integration package connecting AnthropicMessages and LangChain"
optional = false optional = false
python-versions = "<4.0,>=3.8.1" python-versions = "<4.0,>=3.8.1"
files = [ files = [
{file = "langchain_anthropic-0.1.15-py3-none-any.whl", hash = "sha256:7cceea526f473e4d514f39295dc128eec57da628a4bbb54850d11dda7aa959fc"}, {file = "langchain_anthropic-0.1.13-py3-none-any.whl", hash = "sha256:121f6f480da7685c239573d98322adb94fe486d40651ac341637f65da36881de"},
{file = "langchain_anthropic-0.1.15.tar.gz", hash = "sha256:c5c3c6eaccb11ed99a63886e50873ac21eaf8e9441e0f75c7ae7cd8cdef65155"}, {file = "langchain_anthropic-0.1.13.tar.gz", hash = "sha256:32e7ac51e1874c47e1a20493e75f5bfc88b0ffeaf5f1aed6091547e1ae44bb85"},
] ]
[package.dependencies] [package.dependencies]
anthropic = ">=0.28.0,<1" anthropic = ">=0.26.0,<1"
defusedxml = ">=0.7.1,<0.8.0" defusedxml = ">=0.7.1,<0.8.0"
langchain-core = ">=0.2.2rc1,<0.3" langchain-core = ">=0.1.43,<0.3"
[[package]] [[package]]
name = "langchain-astradb" name = "langchain-astradb"
@ -6844,7 +6844,7 @@ files = [
] ]
[package.dependencies] [package.dependencies]
pydantic = ">=2.7.0" pydantic = ">=2.3.0"
python-dotenv = ">=0.21.0" python-dotenv = ">=0.21.0"
[package.extras] [package.extras]
@ -9013,13 +9013,13 @@ types-pyOpenSSL = "*"
[[package]] [[package]]
name = "types-requests" name = "types-requests"
version = "2.32.0.20240602" version = "2.32.0.20240523"
description = "Typing stubs for requests" description = "Typing stubs for requests"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "types-requests-2.32.0.20240602.tar.gz", hash = "sha256:3f98d7bbd0dd94ebd10ff43a7fbe20c3b8528acace6d8efafef0b6a184793f06"}, {file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"},
{file = "types_requests-2.32.0.20240602-py3-none-any.whl", hash = "sha256:ed3946063ea9fbc6b5fc0c44fa279188bae42d582cb63760be6cb4b9d06c3de8"}, {file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"},
] ]
[package.dependencies] [package.dependencies]
@ -9038,13 +9038,13 @@ files = [
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.12.1" version = "4.12.0"
description = "Backported and Experimental Type Hints for Python 3.8+" description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"},
{file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"},
] ]
[[package]] [[package]]
@ -9230,13 +9230,13 @@ files = [
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.30.1" version = "0.29.0"
description = "The lightning-fast ASGI server." description = "The lightning-fast ASGI server."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"}, {file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"}, {file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"},
] ]
[package.dependencies] [package.dependencies]
@ -9300,13 +9300,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)"
[[package]] [[package]]
name = "validators" name = "validators"
version = "0.28.3" version = "0.28.1"
description = "Python Data Validation for Humans™" description = "Python Data Validation for Humans™"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "validators-0.28.3-py3-none-any.whl", hash = "sha256:53cafa854f13850156259d9cc479b864ee901f6a96e6b109e6fc33f98f37d99f"}, {file = "validators-0.28.1-py3-none-any.whl", hash = "sha256:890c98789ad884037f059af6ea915ec2d667129d509180c2c590b8009a4c4219"},
{file = "validators-0.28.3.tar.gz", hash = "sha256:c6c79840bcde9ba77b19f6218f7738188115e27830cbaff43264bc4ed24c429d"}, {file = "validators-0.28.1.tar.gz", hash = "sha256:5ac88e7916c3405f0ce38ac2ac82a477fcf4d90dbbeddd04c8193171fc17f7dc"},
] ]
[[package]] [[package]]
@ -9454,13 +9454,13 @@ files = [
[[package]] [[package]]
name = "weaviate-client" name = "weaviate-client"
version = "4.6.4" version = "4.6.3"
description = "A python native Weaviate client" description = "A python native Weaviate client"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "weaviate_client-4.6.4-py3-none-any.whl", hash = "sha256:19b76fb923a5f0b6fcb7471ef3cd990d2791ede71731e53429e1066a9dbf2af2"}, {file = "weaviate_client-4.6.3-py3-none-any.whl", hash = "sha256:b2921f9aea84a4eccb1c75d55dd2857a87241e5536540fb96ffdf4737ed4fe8a"},
{file = "weaviate_client-4.6.4.tar.gz", hash = "sha256:5378db8a33bf1d48adff3f9efa572d9fb04eaeb36444817cab56f1ba3c595500"}, {file = "weaviate_client-4.6.3.tar.gz", hash = "sha256:a6e638f746f91c310fe6680cffa77949718f17d8b40b966f7037028cacfd94e0"},
] ]
[package.dependencies] [package.dependencies]
@ -9471,7 +9471,7 @@ grpcio-tools = ">=1.57.0,<2.0.0"
httpx = ">=0.25.0,<=0.27.0" httpx = ">=0.25.0,<=0.27.0"
pydantic = ">=2.5.0,<3.0.0" pydantic = ">=2.5.0,<3.0.0"
requests = ">=2.30.0,<3.0.0" requests = ">=2.30.0,<3.0.0"
validators = "0.28.3" validators = "0.28.1"
[[package]] [[package]]
name = "websocket-client" name = "websocket-client"

View file

@ -18,7 +18,7 @@ if not space:
print("Please provide a space to restart.") print("Please provide a space to restart.")
exit() exit()
if not parsed_args.api_token: if not parsed_args.token:
print("Please provide an API token.") print("Please provide an API token.")
exit() exit()

View file

@ -71,9 +71,7 @@ async def login_to_get_access_token(
@router.get("/auto_login") @router.get("/auto_login")
async def auto_login( async def auto_login(
response: Response, response: Response, db: Session = Depends(get_session), settings_service=Depends(get_settings_service)
db: Session = Depends(get_session),
settings_service=Depends(get_settings_service)
): ):
auth_settings = settings_service.auth_settings auth_settings = settings_service.auth_settings
if settings_service.auth_settings.AUTO_LOGIN: if settings_service.auth_settings.AUTO_LOGIN:

View file

@ -1,5 +1,4 @@
from typing import List, Optional from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query from fastapi import APIRouter, Depends, HTTPException, Query
from langflow.services.deps import get_monitor_service from langflow.services.deps import get_monitor_service

View file

@ -15,10 +15,25 @@ import shlex
from collections import OrderedDict, namedtuple from collections import OrderedDict, namedtuple
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from uncurl.api import parser # type: ignore ParsedArgs = namedtuple(
"ParsedContext",
parser.add_argument("-x", "--proxy", default={}) [
parser.add_argument("-U", "--proxy-user", default="") "command",
"url",
"data",
"data_binary",
"method",
"headers",
"compressed",
"insecure",
"user",
"include",
"silent",
"proxy",
"proxy_user",
"cookies",
],
)
ParsedContext = namedtuple("ParsedContext", ["method", "url", "data", "headers", "cookies", "verify", "auth", "proxy"]) ParsedContext = namedtuple("ParsedContext", ["method", "url", "data", "headers", "cookies", "verify", "auth", "proxy"])
@ -27,24 +42,89 @@ def normalize_newlines(multiline_text):
return multiline_text.replace(" \\\n", " ") return multiline_text.replace(" \\\n", " ")
def parse_curl_command(curl_command):
tokens = shlex.split(normalize_newlines(curl_command))
tokens = [token for token in tokens if token and token != " "]
if "curl" not in tokens[0]:
raise ValueError("Invalid curl command")
args_template = {
"command": None,
"url": None,
"data": None,
"data_binary": None,
"method": "get",
"headers": [],
"compressed": False,
"insecure": False,
"user": (),
"include": False,
"silent": False,
"proxy": None,
"proxy_user": None,
"cookies": {},
}
args = args_template.copy()
i = 0
while i < len(tokens):
token = tokens[i]
if token == "-X":
i += 1
args["method"] = tokens[i].lower()
elif token in ("-d", "--data"):
i += 1
args["data"] = tokens[i]
args["method"] = "post"
elif token in ("-b", "--data-binary", "--data-raw"):
i += 1
args["data_binary"] = tokens[i]
args["method"] = "post"
elif token in ("-H", "--header"):
i += 1
args["headers"].append(tokens[i])
elif token == "--compressed":
args["compressed"] = True
elif token in ("-k", "--insecure"):
args["insecure"] = True
elif token in ("-u", "--user"):
i += 1
args["user"] = tuple(tokens[i].split(":"))
elif token in ("-I", "--include"):
args["include"] = True
elif token in ("-s", "--silent"):
args["silent"] = True
elif token in ("-x", "--proxy"):
i += 1
args["proxy"] = tokens[i]
elif token in ("-U", "--proxy-user"):
i += 1
args["proxy_user"] = tokens[i]
elif not token.startswith("-"):
if args["command"] is None:
args["command"] = token
else:
args["url"] = token
i += 1
return ParsedArgs(**args)
def parse_context(curl_command): def parse_context(curl_command):
method = "get" method = "get"
tokens = shlex.split(normalize_newlines(curl_command)) parsed_args: ParsedArgs = parse_curl_command(curl_command)
tokens = [token for token in tokens if token and token != " "]
parsed_args = parser.parse_args(tokens)
post_data = parsed_args.data or parsed_args.data_binary post_data = parsed_args.data or parsed_args.data_binary
if post_data: if post_data:
method = "post" method = "post"
if parsed_args.X: if parsed_args.method:
method = parsed_args.X.lower() method = parsed_args.method.lower()
cookie_dict = OrderedDict() cookie_dict = OrderedDict()
quoted_headers = OrderedDict() quoted_headers = OrderedDict()
for curl_header in parsed_args.header: for curl_header in parsed_args.headers:
if curl_header.startswith(":"): if curl_header.startswith(":"):
occurrence = [m.start() for m in re.finditer(":", curl_header)] occurrence = [m.start() for m in re.finditer(":", curl_header)]
header_key, header_value = curl_header[: occurrence[1]], curl_header[occurrence[1] + 1 :] header_key, header_value = curl_header[: occurrence[1]], curl_header[occurrence[1] + 1 :]

View file

@ -99,7 +99,7 @@ def read_text_file(file_path: str) -> str:
with open(file_path, "rb") as f: with open(file_path, "rb") as f:
raw_data = f.read() raw_data = f.read()
result = chardet.detect(raw_data) result = chardet.detect(raw_data)
encoding = result['encoding'] encoding = result["encoding"]
with open(file_path, "r", encoding=encoding) as f: with open(file_path, "r", encoding=encoding) as f:
return f.read() return f.read()

View file

@ -90,7 +90,9 @@ async def run_flow(
fallback_to_env_vars = get_settings_service().settings.fallback_to_env_var fallback_to_env_vars = get_settings_service().settings.fallback_to_env_var
return await graph.arun(inputs_list, inputs_components=inputs_components, types=types, fallback_to_env_vars=fallback_to_env_vars) return await graph.arun(
inputs_list, inputs_components=inputs_components, types=types, fallback_to_env_vars=fallback_to_env_vars
)
def generate_function_for_flow( def generate_function_for_flow(

View file

@ -20,7 +20,7 @@ from langflow.services.database.models.user.crud import get_user_by_username
from langflow.services.deps import get_settings_service, session_scope from langflow.services.deps import get_settings_service, session_scope
from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist
from langflow.services.deps import get_settings_service, session_scope, get_variable_service from langflow.services.deps import get_variable_service
STARTER_FOLDER_NAME = "Starter Projects" STARTER_FOLDER_NAME = "Starter Projects"
@ -221,6 +221,7 @@ def _is_valid_uuid(val):
return False return False
return str(uuid_obj) == val return str(uuid_obj) == val
def load_flows_from_directory(): def load_flows_from_directory():
settings_service = get_settings_service() settings_service = get_settings_service()
flows_path = settings_service.settings.load_flows_path flows_path = settings_service.settings.load_flows_path
@ -262,6 +263,7 @@ def load_flows_from_directory():
session.add(flow) session.add(flow)
session.commit() session.commit()
def find_existing_flow(session, flow_id, flow_endpoint_name): def find_existing_flow(session, flow_id, flow_endpoint_name):
if flow_endpoint_name: if flow_endpoint_name:
stmt = select(Flow).where(Flow.endpoint_name == flow_endpoint_name) stmt = select(Flow).where(Flow.endpoint_name == flow_endpoint_name)
@ -271,6 +273,8 @@ def find_existing_flow(session, flow_id, flow_endpoint_name):
if existing := session.exec(stmt).first(): if existing := session.exec(stmt).first():
return existing return existing
return None return None
def create_or_update_starter_projects(): def create_or_update_starter_projects():
components_paths = get_settings_service().settings.components_path components_paths = get_settings_service().settings.components_path
try: try:

View file

@ -59,7 +59,7 @@ async def run_graph_internal(
outputs or [], outputs or [],
stream=stream, stream=stream,
session_id=session_id_str or "", session_id=session_id_str or "",
fallback_to_env_vars=fallback_to_env_vars fallback_to_env_vars=fallback_to_env_vars,
) )
if session_id_str and session_service: if session_id_str and session_service:
await session_service.update_session(session_id_str, (graph, artifacts)) await session_service.update_session(session_id_str, (graph, artifacts))

View file

@ -215,10 +215,7 @@ def create_user_longterm_token(db: Session = Depends(get_session)) -> tuple[UUID
username = settings_service.auth_settings.SUPERUSER username = settings_service.auth_settings.SUPERUSER
super_user = get_user_by_username(db, username) super_user = get_user_by_username(db, username)
if not super_user: if not super_user:
raise HTTPException( raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Super user hasn't been created")
status_code=status.HTTP_400_BAD_REQUEST,
detail="Super user hasn't been created"
)
access_token_expires_longterm = timedelta(days=365) access_token_expires_longterm = timedelta(days=365)
access_token = create_token( access_token = create_token(
data={"sub": str(super_user.id)}, data={"sub": str(super_user.id)},

View file

@ -55,6 +55,7 @@ class ApiKeyRead(ApiKeyBase):
id: UUID id: UUID
api_key: str = Field(schema_extra={"validate_default": True}) api_key: str = Field(schema_extra={"validate_default": True})
user_id: UUID = Field() user_id: UUID = Field()
created_at: datetime = Field()
@field_validator("api_key") @field_validator("api_key")
@classmethod @classmethod

View file

@ -1,5 +1,4 @@
import os import os
from typing import Optional
import yaml import yaml
from loguru import logger from loguru import logger
@ -8,6 +7,7 @@ from langflow.services.base import Service
from langflow.services.settings.auth import AuthSettings from langflow.services.settings.auth import AuthSettings
from langflow.services.settings.base import Settings from langflow.services.settings.base import Settings
class SettingsService(Service): class SettingsService(Service):
name = "settings_service" name = "settings_service"

View file

@ -44,6 +44,7 @@
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"dompurify": "^3.0.5", "dompurify": "^3.0.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"emoji-regex": "^10.3.0",
"esbuild": "^0.17.19", "esbuild": "^0.17.19",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"framer-motion": "^11.0.6", "framer-motion": "^11.0.6",
@ -5997,9 +5998,9 @@
"integrity": "sha512-NPtACGFe7vunRYzvYqVRhQvsDrTevxpgDKxG/Vcbe0BTNOY+5+/2mOXSw2ls7ToNbE5Bf/+uQbjTxcmwMozpCw==" "integrity": "sha512-NPtACGFe7vunRYzvYqVRhQvsDrTevxpgDKxG/Vcbe0BTNOY+5+/2mOXSw2ls7ToNbE5Bf/+uQbjTxcmwMozpCw=="
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "8.0.0", "version": "10.3.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
}, },
"node_modules/end-of-stream": { "node_modules/end-of-stream": {
"version": "1.4.4", "version": "1.4.4",
@ -12205,6 +12206,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/string-width/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/strip-ansi": { "node_modules/strip-ansi": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",

View file

@ -39,6 +39,7 @@
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"dompurify": "^3.0.5", "dompurify": "^3.0.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"emoji-regex": "^10.3.0",
"esbuild": "^0.17.19", "esbuild": "^0.17.19",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"framer-motion": "^11.0.6", "framer-motion": "^11.0.6",

View file

@ -164,3 +164,13 @@ body {
.ag-body-vertical-scroll-viewport::-webkit-scrollbar-thumb:hover { .ag-body-vertical-scroll-viewport::-webkit-scrollbar-thumb:hover {
background-color: #bbb; background-color: #bbb;
} }
/* This CSS is to not apply the border for the column having 'no-border' class */
.no-border.ag-cell:focus {
border: none !important;
outline: none;
}
.no-border.ag-cell {
border: none !important;
outline: none;
}

View file

@ -1,4 +1,3 @@
import axios from "axios";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { ErrorBoundary } from "react-error-boundary"; import { ErrorBoundary } from "react-error-boundary";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -30,10 +29,10 @@ export default function App() {
useTrackLastVisitedPath(); useTrackLastVisitedPath();
const removeFromTempNotificationList = useAlertStore( const removeFromTempNotificationList = useAlertStore(
(state) => state.removeFromTempNotificationList, (state) => state.removeFromTempNotificationList
); );
const tempNotificationList = useAlertStore( const tempNotificationList = useAlertStore(
(state) => state.tempNotificationList, (state) => state.tempNotificationList
); );
const [fetchError, setFetchError] = useState(false); const [fetchError, setFetchError] = useState(false);
const isLoading = useFlowsManagerStore((state) => state.isLoading); const isLoading = useFlowsManagerStore((state) => state.isLoading);
@ -51,7 +50,7 @@ export default function App() {
const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshVersion = useDarkStore((state) => state.refreshVersion);
const refreshStars = useDarkStore((state) => state.refreshStars); const refreshStars = useDarkStore((state) => state.refreshStars);
const setGlobalVariables = useGlobalVariablesStore( const setGlobalVariables = useGlobalVariablesStore(
(state) => state.setGlobalVariables, (state) => state.setGlobalVariables
); );
const checkHasStore = useStoreStore((state) => state.checkHasStore); const checkHasStore = useStoreStore((state) => state.checkHasStore);
const navigate = useNavigate(); const navigate = useNavigate();

View file

@ -16,13 +16,13 @@ export default function AlertDropdown({
}: AlertDropdownType): JSX.Element { }: AlertDropdownType): JSX.Element {
const notificationList = useAlertStore((state) => state.notificationList); const notificationList = useAlertStore((state) => state.notificationList);
const clearNotificationList = useAlertStore( const clearNotificationList = useAlertStore(
(state) => state.clearNotificationList, (state) => state.clearNotificationList
); );
const removeFromNotificationList = useAlertStore( const removeFromNotificationList = useAlertStore(
(state) => state.removeFromNotificationList, (state) => state.removeFromNotificationList
); );
const setNotificationCenter = useAlertStore( const setNotificationCenter = useAlertStore(
(state) => state.setNotificationCenter, (state) => state.setNotificationCenter
); );
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);

View file

@ -31,14 +31,14 @@ export default function ImageViewer({ image }) {
const fullPageButton = document.getElementById("full-page-button"); const fullPageButton = document.getElementById("full-page-button");
zoomInButton!.addEventListener("click", () => zoomInButton!.addEventListener("click", () =>
viewer.viewport.zoomBy(1.2), viewer.viewport.zoomBy(1.2)
); );
zoomOutButton!.addEventListener("click", () => zoomOutButton!.addEventListener("click", () =>
viewer.viewport.zoomBy(0.8), viewer.viewport.zoomBy(0.8)
); );
homeButton!.addEventListener("click", () => viewer.viewport.goHome()); homeButton!.addEventListener("click", () => viewer.viewport.goHome());
fullPageButton!.addEventListener("click", () => fullPageButton!.addEventListener("click", () =>
viewer.setFullScreen(true), viewer.setFullScreen(true)
); );
// Optionally, you can set additional viewer options here // Optionally, you can set additional viewer options here
@ -47,16 +47,16 @@ export default function ImageViewer({ image }) {
return () => { return () => {
viewer.destroy(); viewer.destroy();
zoomInButton!.removeEventListener("click", () => zoomInButton!.removeEventListener("click", () =>
viewer.viewport.zoomBy(1.2), viewer.viewport.zoomBy(1.2)
); );
zoomOutButton!.removeEventListener("click", () => zoomOutButton!.removeEventListener("click", () =>
viewer.viewport.zoomBy(0.8), viewer.viewport.zoomBy(0.8)
); );
homeButton!.removeEventListener("click", () => homeButton!.removeEventListener("click", () =>
viewer.viewport.goHome(), viewer.viewport.goHome()
); );
fullPageButton!.removeEventListener("click", () => fullPageButton!.removeEventListener("click", () =>
viewer.setFullScreen(true), viewer.setFullScreen(true)
); );
}; };
} }

View file

@ -7,7 +7,6 @@ import {
} from "../../components/ui/accordion"; } from "../../components/ui/accordion";
import { AccordionComponentType } from "../../types/components"; import { AccordionComponentType } from "../../types/components";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import ShadTooltip from "../shadTooltipComponent";
export default function AccordionComponent({ export default function AccordionComponent({
trigger, trigger,
@ -18,7 +17,7 @@ export default function AccordionComponent({
sideBar, sideBar,
}: AccordionComponentType): JSX.Element { }: AccordionComponentType): JSX.Element {
const [value, setValue] = useState( const [value, setValue] = useState(
open.length === 0 ? "" : getOpenAccordion(), open.length === 0 ? "" : getOpenAccordion()
); );
function getOpenAccordion(): string { function getOpenAccordion(): string {
@ -53,7 +52,7 @@ export default function AccordionComponent({
disabled={disabled} disabled={disabled}
className={cn( className={cn(
sideBar ? "w-full bg-muted px-[0.75rem] py-[0.5rem]" : "ml-3", sideBar ? "w-full bg-muted px-[0.75rem] py-[0.5rem]" : "ml-3",
disabled ? "cursor-not-allowed" : "cursor-pointer", disabled ? "cursor-not-allowed" : "cursor-pointer"
)} )}
> >
{trigger} {trigger}

View file

@ -27,8 +27,8 @@ import {
import { Checkbox } from "../ui/checkbox"; import { Checkbox } from "../ui/checkbox";
import { FormControl, FormField } from "../ui/form"; import { FormControl, FormField } from "../ui/form";
import Loading from "../ui/loading"; import Loading from "../ui/loading";
import { convertTestName } from "./utils/convert-test-name";
import DragCardComponent from "./components/dragCardComponent"; import DragCardComponent from "./components/dragCardComponent";
import { convertTestName } from "./utils/convert-test-name";
export default function CollectionCardComponent({ export default function CollectionCardComponent({
data, data,
@ -60,11 +60,11 @@ export default function CollectionCardComponent({
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingLike, setLoadingLike] = useState(false); const [loadingLike, setLoadingLike] = useState(false);
const [liked_by_user, setLiked_by_user] = useState( const [liked_by_user, setLiked_by_user] = useState(
data?.liked_by_user ?? false, data?.liked_by_user ?? false
); );
const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0); const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0);
const [downloads_count, setDownloads_count] = useState( const [downloads_count, setDownloads_count] = useState(
data?.downloads_count ?? 0, data?.downloads_count ?? 0
); );
const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
@ -75,12 +75,12 @@ export default function CollectionCardComponent({
const [openPlayground, setOpenPlayground] = useState(false); const [openPlayground, setOpenPlayground] = useState(false);
const [openDelete, setOpenDelete] = useState(false); const [openDelete, setOpenDelete] = useState(false);
const setCurrentFlowId = useFlowsManagerStore( const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId, (state) => state.setCurrentFlowId
); );
const [loadingPlayground, setLoadingPlayground] = useState(false); const [loadingPlayground, setLoadingPlayground] = useState(false);
const selectedFlowsComponentsCards = useFlowsManagerStore( const selectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.selectedFlowsComponentsCards, (state) => state.selectedFlowsComponentsCards
); );
const name = data.is_component ? "Component" : "Flow"; const name = data.is_component ? "Component" : "Flow";
@ -220,7 +220,7 @@ export default function CollectionCardComponent({
"group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]", "group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]",
disabled ? "pointer-events-none opacity-50" : "", disabled ? "pointer-events-none opacity-50" : "",
onClick ? "cursor-pointer" : "", onClick ? "cursor-pointer" : "",
isSelectedCard ? "border border-selected" : "", isSelectedCard ? "border border-selected" : ""
)} )}
onClick={onClick} onClick={onClick}
> >
@ -233,7 +233,7 @@ export default function CollectionCardComponent({
"visible flex-shrink-0", "visible flex-shrink-0",
data.is_component data.is_component
? "mx-0.5 h-6 w-6 text-component-icon" ? "mx-0.5 h-6 w-6 text-component-icon"
: "h-7 w-7 flex-shrink-0 text-flow-icon", : "h-7 w-7 flex-shrink-0 text-flow-icon"
)} )}
name={data.is_component ? "ToyBrick" : "Group"} name={data.is_component ? "ToyBrick" : "Group"}
/> />
@ -428,7 +428,7 @@ export default function CollectionCardComponent({
name="Trash2" name="Trash2"
className={cn( className={cn(
"h-5 w-5", "h-5 w-5",
!authorized ? " text-ring" : "", !authorized ? " text-ring" : ""
)} )}
/> />
</Button> </Button>
@ -463,7 +463,7 @@ export default function CollectionCardComponent({
liked_by_user liked_by_user
? "fill-destructive stroke-destructive" ? "fill-destructive stroke-destructive"
: "", : "",
!authorized ? " text-ring" : "", !authorized ? " text-ring" : ""
)} )}
/> />
</Button> </Button>
@ -501,7 +501,7 @@ export default function CollectionCardComponent({
} }
className={cn( className={cn(
loading ? "h-5 w-5 animate-spin" : "h-5 w-5", loading ? "h-5 w-5 animate-spin" : "h-5 w-5",
!authorized ? " text-ring" : "", !authorized ? " text-ring" : ""
)} )}
/> />
</Button> </Button>

View file

@ -65,7 +65,7 @@ export default function CardsWrapComponent({
"h-full w-full", "h-full w-full",
isDragging isDragging
? "mb-36 flex flex-col items-center justify-center gap-4 text-2xl font-light" ? "mb-36 flex flex-col items-center justify-center gap-4 text-2xl font-light"
: "", : ""
)} )}
> >
{isDragging ? ( {isDragging ? (

View file

@ -50,7 +50,7 @@ export default function FlowToolbar(): JSX.Element {
"relative inline-flex h-full w-full items-center justify-center gap-[4px] bg-muted px-5 py-3 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-background hover:bg-hover ", "relative inline-flex h-full w-full items-center justify-center gap-[4px] bg-muted px-5 py-3 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-background hover:bg-hover ",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? " button-disable text-muted-foreground " ? " button-disable text-muted-foreground "
: "", : ""
)} )}
> >
<ForwardedIconComponent <ForwardedIconComponent
@ -59,14 +59,14 @@ export default function FlowToolbar(): JSX.Element {
"-m-0.5 -ml-1 h-6 w-6", "-m-0.5 -ml-1 h-6 w-6",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? "extra-side-bar-save-disable" ? "extra-side-bar-save-disable"
: "", : ""
)} )}
/> />
Share Share
</button> </button>
</ShareModal> </ShareModal>
), ),
[hasApiKey, validApiKey, currentFlow, hasStore], [hasApiKey, validApiKey, currentFlow, hasStore]
); );
return ( return (
@ -118,7 +118,7 @@ export default function FlowToolbar(): JSX.Element {
<ApiModal flow={currentFlow}> <ApiModal flow={currentFlow}>
<div <div
className={classNames( className={classNames(
"relative inline-flex w-full items-center justify-center gap-1 px-5 py-3 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-hover", "relative inline-flex w-full items-center justify-center gap-1 px-5 py-3 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-hover"
)} )}
> >
<ForwardedIconComponent <ForwardedIconComponent

View file

@ -236,7 +236,7 @@ export default function CodeTabsComponent({
<div className="api-modal-according-display"> <div className="api-modal-according-display">
<div <div
className={classNames( className={classNames(
"h-[70vh] w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll", "h-[70vh] w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll"
)} )}
> >
{data?.map((node: any, i) => ( {data?.map((node: any, i) => (
@ -275,8 +275,8 @@ export default function CodeTabsComponent({
.show && .show &&
LANGFLOW_SUPPORTED_TYPES.has( LANGFLOW_SUPPORTED_TYPES.has(
node.data.node.template[templateField] node.data.node.template[templateField]
.type, .type
), )
) )
.map((templateField, indx) => { .map((templateField, indx) => {
return ( return (
@ -334,7 +334,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -380,7 +380,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -433,7 +433,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -470,7 +470,7 @@ export default function CodeTabsComponent({
e, e,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
size="small" size="small"
@ -501,7 +501,7 @@ export default function CodeTabsComponent({
].fileTypes ].fileTypes
} }
onFileChange={( onFileChange={(
value: any, value: any
) => { ) => {
node.data.node.template[ node.data.node.template[
templateField templateField
@ -554,7 +554,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -594,7 +594,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
value={ value={
@ -656,7 +656,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -702,7 +702,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -748,7 +748,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />
@ -780,8 +780,8 @@ export default function CodeTabsComponent({
].value, ].value,
type( type(
node, node,
templateField, templateField
), )
) )
} }
duplicateKey={ duplicateKey={
@ -790,15 +790,15 @@ export default function CodeTabsComponent({
onChange={(target) => { onChange={(target) => {
const valueToNumbers = const valueToNumbers =
convertValuesToNumbers( convertValuesToNumbers(
target, target
); );
node.data.node!.template[ node.data.node!.template[
templateField templateField
].value = valueToNumbers; ].value = valueToNumbers;
setErrorDuplicateKey( setErrorDuplicateKey(
hasDuplicateKeys( hasDuplicateKeys(
valueToNumbers, valueToNumbers
), )
); );
setData((old) => { setData((old) => {
let newInputList = let newInputList =
@ -815,7 +815,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
isList={ isList={
@ -863,7 +863,7 @@ export default function CodeTabsComponent({
target, target,
node.data.node.template[ node.data.node.template[
templateField templateField
], ]
); );
}} }}
/> />

View file

@ -67,7 +67,7 @@ function CsvOutputComponent({
if (file) { if (file) {
const { rowData: data, colDefs: columns } = convertCSVToData( const { rowData: data, colDefs: columns } = convertCSVToData(
file, file,
separator, separator
); );
setRowData(data); setRowData(data);
setColDefs(columns); setColDefs(columns);

View file

@ -29,7 +29,7 @@ export default function DictComponent({
<div <div
className={classNames( className={classNames(
value.length > 1 && editNode ? "my-1" : "", value.length > 1 && editNode ? "my-1" : "",
"flex flex-col gap-3", "flex flex-col gap-3"
)} )}
> >
{ {

View file

@ -33,9 +33,8 @@ export default function Dropdown({
const refButton = useRef<HTMLButtonElement>(null); const refButton = useRef<HTMLButtonElement>(null);
const PopoverContentDropdown = children const PopoverContentDropdown =
? PopoverContent children || editNode ? PopoverContent : PopoverContentWithoutPortal;
: PopoverContentWithoutPortal;
return ( return (
<> <>

View file

@ -99,7 +99,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
<span <span
className={cn( className={cn(
"font-normal text-muted-foreground word-break-break-word", "font-normal text-muted-foreground word-break-break-word",
description === "" ? "font-light italic" : "", description === "" ? "font-light italic" : ""
)} )}
> >
{description === "" ? "No description" : description} {description === "" ? "No description" : description}

View file

@ -113,7 +113,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
title: UPLOAD_ERROR_ALERT, title: UPLOAD_ERROR_ALERT,
list: [error], list: [error],
}); });
}, }
); );
}} }}
> >
@ -195,7 +195,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"} name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"}
className={cn( className={cn(
"h-4 w-4", "h-4 w-4",
isBuilding || saveLoading ? "animate-spin" : "animate-wiggle", isBuilding || saveLoading ? "animate-spin" : "animate-wiggle"
)} )}
/> />
{printByBuildStatus()} {printByBuildStatus()}

View file

@ -181,18 +181,6 @@ export default function Header(): JSX.Element {
/> />
</div> </div>
</AlertDropdown> </AlertDropdown>
{autoLogin && (
<button
onClick={() => {
navigate("/account/api-keys");
}}
>
<IconComponent
name="Key"
className="side-bar-button-size text-muted-foreground hover:text-accent-foreground"
/>
</button>
)}
<> <>
<Separator orientation="vertical" /> <Separator orientation="vertical" />

View file

@ -10,7 +10,11 @@ import {
CommandList, CommandList,
} from "../../../ui/command"; } from "../../../ui/command";
import { Input } from "../../../ui/input"; import { Input } from "../../../ui/input";
import { Popover, PopoverContentWithoutPortal } from "../../../ui/popover"; import {
Popover,
PopoverContent,
PopoverContentWithoutPortal,
} from "../../../ui/popover";
const CustomInputPopover = ({ const CustomInputPopover = ({
id, id,
refInput, refInput,
@ -39,6 +43,9 @@ const CustomInputPopover = ({
showOptions, showOptions,
}) => { }) => {
const setErrorData = useAlertStore.getState().setErrorData; const setErrorData = useAlertStore.getState().setErrorData;
const PopoverContentInput = editNode
? PopoverContent
: PopoverContentWithoutPortal;
const handleInputChange = (e) => { const handleInputChange = (e) => {
if (password) { if (password) {
@ -96,7 +103,7 @@ const CustomInputPopover = ({
(password && !(setSelectedOption || setSelectedOptions)) (password && !(setSelectedOption || setSelectedOptions))
? "pr-8" ? "pr-8"
: "", : "",
className!, className!
)} )}
placeholder={password && editNode ? "Key" : placeholder} placeholder={password && editNode ? "Key" : placeholder}
onChange={handleInputChange} onChange={handleInputChange}
@ -107,7 +114,7 @@ const CustomInputPopover = ({
data-testid={editNode ? id + "-edit" : id} data-testid={editNode ? id + "-edit" : id}
/> />
</PopoverAnchor> </PopoverAnchor>
<PopoverContentWithoutPortal <PopoverContentInput
className="nocopy nowheel nopan nodelete nodrag noundo p-0" className="nocopy nowheel nopan nodelete nodrag noundo p-0"
style={{ minWidth: refInput?.current?.clientWidth ?? "200px" }} style={{ minWidth: refInput?.current?.clientWidth ?? "200px" }}
side="bottom" side="bottom"
@ -134,15 +141,15 @@ const CustomInputPopover = ({
onSelect={(currentValue) => { onSelect={(currentValue) => {
setSelectedOption && setSelectedOption &&
setSelectedOption( setSelectedOption(
currentValue === selectedOption ? "" : currentValue, currentValue === selectedOption ? "" : currentValue
); );
setSelectedOptions && setSelectedOptions &&
setSelectedOptions( setSelectedOptions(
selectedOptions?.includes(currentValue) selectedOptions?.includes(currentValue)
? selectedOptions.filter( ? selectedOptions.filter(
(item) => item !== currentValue, (item) => item !== currentValue
) )
: [...selectedOptions, currentValue], : [...selectedOptions, currentValue]
); );
!setSelectedOptions && setShowOptions(false); !setSelectedOptions && setShowOptions(false);
}} }}
@ -155,7 +162,7 @@ const CustomInputPopover = ({
selectedOption === option || selectedOption === option ||
selectedOptions?.includes(option) selectedOptions?.includes(option)
? "opacity-100" ? "opacity-100"
: "opacity-0", : "opacity-0"
)} )}
> >
<div className="absolute opacity-100 transition-all group-hover:opacity-0"> <div className="absolute opacity-100 transition-all group-hover:opacity-0">
@ -184,7 +191,7 @@ const CustomInputPopover = ({
</CommandGroup> </CommandGroup>
</CommandList> </CommandList>
</Command> </Command>
</PopoverContentWithoutPortal> </PopoverContentInput>
</Popover> </Popover>
); );
}; };

View file

@ -9,7 +9,11 @@ import {
CommandList, CommandList,
} from "../../../ui/command"; } from "../../../ui/command";
import { Input } from "../../../ui/input"; import { Input } from "../../../ui/input";
import { Popover, PopoverContentWithoutPortal } from "../../../ui/popover"; import {
Popover,
PopoverContent,
PopoverContentWithoutPortal,
} from "../../../ui/popover";
const CustomInputPopoverObject = ({ const CustomInputPopoverObject = ({
id, id,
refInput, refInput,
@ -23,6 +27,7 @@ const CustomInputPopoverObject = ({
disabled, disabled,
setShowOptions, setShowOptions,
required, required,
editNode,
className, className,
placeholder, placeholder,
onChange, onChange,
@ -34,6 +39,10 @@ const CustomInputPopoverObject = ({
handleKeyDown, handleKeyDown,
showOptions, showOptions,
}) => { }) => {
const PopoverContentInput = editNode
? PopoverContent
: PopoverContentWithoutPortal;
const handleInputChange = (e) => { const handleInputChange = (e) => {
onChange && onChange(e.target.value); onChange && onChange(e.target.value);
}; };
@ -55,7 +64,7 @@ const CustomInputPopoverObject = ({
? selectedOptions ? selectedOptions
.map( .map(
(optionId) => (optionId) =>
options.find((option) => option.id === optionId)?.name, options.find((option) => option.id === optionId)?.name
) )
.join(", ") .join(", ")
: value : value
@ -79,7 +88,7 @@ const CustomInputPopoverObject = ({
data-testid={id} data-testid={id}
/> />
</PopoverAnchor> </PopoverAnchor>
<PopoverContentWithoutPortal <PopoverContentInput
className="nocopy nowheel nopan nodelete nodrag noundo p-0" className="nocopy nowheel nopan nodelete nodrag noundo p-0"
style={{ minWidth: refInput?.current?.clientWidth ?? "200px" }} style={{ minWidth: refInput?.current?.clientWidth ?? "200px" }}
side="bottom" side="bottom"
@ -106,15 +115,15 @@ const CustomInputPopoverObject = ({
onSelect={(currentValue) => { onSelect={(currentValue) => {
setSelectedOption && setSelectedOption &&
setSelectedOption( setSelectedOption(
currentValue === selectedOption ? "" : currentValue, currentValue === selectedOption ? "" : currentValue
); );
setSelectedOptions && setSelectedOptions &&
setSelectedOptions( setSelectedOptions(
selectedOptions?.includes(currentValue) selectedOptions?.includes(currentValue)
? selectedOptions.filter( ? selectedOptions.filter(
(item) => item !== currentValue, (item) => item !== currentValue
) )
: [...selectedOptions, currentValue], : [...selectedOptions, currentValue]
); );
!setSelectedOptions && setShowOptions(false); !setSelectedOptions && setShowOptions(false);
}} }}
@ -127,7 +136,7 @@ const CustomInputPopoverObject = ({
selectedOption === option.id || selectedOption === option.id ||
selectedOptions?.includes(option.id) selectedOptions?.includes(option.id)
? "opacity-100" ? "opacity-100"
: "opacity-0", : "opacity-0"
)} )}
> >
<div className="absolute opacity-100 transition-all group-hover:opacity-0"> <div className="absolute opacity-100 transition-all group-hover:opacity-0">
@ -159,7 +168,7 @@ const CustomInputPopoverObject = ({
</CommandGroup> </CommandGroup>
</CommandList> </CommandList>
</Command> </Command>
</PopoverContentWithoutPortal> </PopoverContentInput>
</Popover> </Popover>
); );
}; };

View file

@ -71,7 +71,7 @@ export default function InputComponent({
editNode ? " input-edit-node " : "", editNode ? " input-edit-node " : "",
password && editNode ? "pr-8" : "", password && editNode ? "pr-8" : "",
password && !editNode ? "pr-10" : "", password && !editNode ? "pr-10" : "",
className!, className!
)} )}
placeholder={password && editNode ? "Key" : placeholder} placeholder={password && editNode ? "Key" : placeholder}
onChange={(e) => { onChange={(e) => {
@ -108,6 +108,7 @@ export default function InputComponent({
setSelectedOptions={setSelectedOptions} setSelectedOptions={setSelectedOptions}
options={objectOptions} options={objectOptions}
value={value} value={value}
editNode={editNode}
autoFocus={autoFocus} autoFocus={autoFocus}
disabled={disabled} disabled={disabled}
setShowOptions={setShowOptions} setShowOptions={setShowOptions}
@ -153,7 +154,7 @@ export default function InputComponent({
<span <span
className={cn( className={cn(
password && selectedOption === "" ? "right-8" : "right-0", password && selectedOption === "" ? "right-8" : "right-0",
"absolute inset-y-0 flex items-center pr-2.5", "absolute inset-y-0 flex items-center pr-2.5"
)} )}
> >
<button <button
@ -166,7 +167,7 @@ export default function InputComponent({
selectedOption !== "" selectedOption !== ""
? "text-medium-indigo" ? "text-medium-indigo"
: "text-muted-foreground", : "text-muted-foreground",
"hover:text-accent-foreground", "hover:text-accent-foreground"
)} )}
> >
<ForwardedIconComponent <ForwardedIconComponent
@ -186,7 +187,7 @@ export default function InputComponent({
"mb-px", "mb-px",
editNode editNode
? "input-component-true-button" ? "input-component-true-button"
: "input-component-false-button", : "input-component-false-button"
)} )}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -203,7 +204,7 @@ export default function InputComponent({
className={classNames( className={classNames(
editNode editNode
? "input-component-true-svg" ? "input-component-true-svg"
: "input-component-false-svg", : "input-component-false-svg"
)} )}
> >
<path <path
@ -222,7 +223,7 @@ export default function InputComponent({
className={classNames( className={classNames(
editNode editNode
? "input-component-true-svg" ? "input-component-true-svg"
: "input-component-false-svg", : "input-component-false-svg"
)} )}
> >
<path <path

View file

@ -1,7 +1,6 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { import {
CONSOLE_ERROR_MSG, CONSOLE_ERROR_MSG,
CONSOLE_SUCCESS_MSG,
INVALID_FILE_ALERT, INVALID_FILE_ALERT,
} from "../../constants/alerts_constants"; } from "../../constants/alerts_constants";
import { uploadFile } from "../../controllers/API"; import { uploadFile } from "../../controllers/API";

View file

@ -32,11 +32,11 @@ export default function InputGlobalComponent({
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
useEffect(() => { useEffect(() => {
if (data.node?.template[name]) if (data)
if ( if (
globalVariablesEntries && globalVariablesEntries &&
!globalVariablesEntries.includes(data.node?.template[name].value) && !globalVariablesEntries.includes(data.value) &&
data.node?.template[name].load_from_db data.load_from_db
) { ) {
setTimeout(() => { setTimeout(() => {
onChange("", true); onChange("", true);
@ -46,17 +46,11 @@ export default function InputGlobalComponent({
}, [globalVariablesEntries]); }, [globalVariablesEntries]);
useEffect(() => { useEffect(() => {
if ( if (!data.value && data.display_name) {
!data.node?.template[name].value && if (unavaliableFields[data.display_name!] && !disabled) {
data.node?.template[name].display_name
) {
if (
unavaliableFields[data.node?.template[name].display_name!] &&
!disabled
) {
setTimeout(() => { setTimeout(() => {
setDb(true); setDb(true);
onChange(unavaliableFields[data.node?.template[name].display_name!]); onChange(unavaliableFields[data.display_name!]);
}, 100); }, 100);
} }
} }
@ -68,10 +62,7 @@ export default function InputGlobalComponent({
await deleteGlobalVariable(id) await deleteGlobalVariable(id)
.then(() => { .then(() => {
removeGlobalVariable(key); removeGlobalVariable(key);
if ( if (data?.value === key && data?.load_from_db) {
data?.node?.template[name].value === key &&
data?.node?.template[name].load_from_db
) {
onChange(""); onChange("");
setDb(false); setDb(false);
} }
@ -94,8 +85,8 @@ export default function InputGlobalComponent({
id={"input-" + name} id={"input-" + name}
editNode={editNode} editNode={editNode}
disabled={disabled} disabled={disabled}
password={data.node?.template[name].password ?? false} password={data.password ?? false}
value={data.node?.template[name].value ?? ""} value={data.value ?? ""}
options={globalVariablesEntries} options={globalVariablesEntries}
optionsPlaceholder={"Global Variables"} optionsPlaceholder={"Global Variables"}
optionsIcon="Globe" optionsIcon="Globe"
@ -138,10 +129,10 @@ export default function InputGlobalComponent({
</DeleteConfirmationModal> </DeleteConfirmationModal>
)} )}
selectedOption={ selectedOption={
data?.node?.template[name].load_from_db && data?.load_from_db &&
globalVariablesEntries && globalVariablesEntries &&
globalVariablesEntries.includes(data?.node?.template[name].value ?? "") globalVariablesEntries.includes(data?.value ?? "")
? data?.node?.template[name].value ? data?.value
: "" : ""
} }
setSelectedOption={(value) => { setSelectedOption={(value) => {

View file

@ -11,7 +11,7 @@ export default function ShadTooltip({
delayDuration = 500, delayDuration = 500,
}: ShadToolTipType): JSX.Element { }: ShadToolTipType): JSX.Element {
return ( return (
<Tooltip delayDuration={delayDuration}> <Tooltip defaultOpen={!children} delayDuration={delayDuration}>
<TooltipTrigger asChild={asChild}>{children}</TooltipTrigger> <TooltipTrigger asChild={asChild}>{children}</TooltipTrigger>
<TooltipContent <TooltipContent
className={cn(styleClasses, "max-w-96")} className={cn(styleClasses, "max-w-96")}

View file

@ -1,7 +1,6 @@
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { cn } from "../../../../utils/utils"; import { cn } from "../../../../utils/utils";
import { buttonVariants } from "../../../ui/button"; import { buttonVariants } from "../../../ui/button";
import ForwardedIconComponent from "../../../genericIconComponent";
type SideBarButtonsComponentProps = { type SideBarButtonsComponentProps = {
items: { items: {
@ -28,7 +27,7 @@ const SideBarButtonsComponent = ({
pathname === item.href pathname === item.href
? "border border-border bg-muted hover:bg-muted" ? "border border-border bg-muted hover:bg-muted"
: "border border-transparent hover:border-border hover:bg-transparent", : "border border-transparent hover:border-border hover:bg-transparent",
"flex w-full shrink-0 justify-start gap-4", "flex w-full shrink-0 justify-start gap-4"
)} )}
> >
{item.icon} {item.icon}

View file

@ -12,7 +12,7 @@ import { addVersionToDuplicates } from "../../../utils/reactflowUtils";
const useFileDrop = (folderId, folderChangeCallback) => { const useFileDrop = (folderId, folderChangeCallback) => {
const setFolderDragging = useFolderStore((state) => state.setFolderDragging); const setFolderDragging = useFolderStore((state) => state.setFolderDragging);
const setFolderIdDragging = useFolderStore( const setFolderIdDragging = useFolderStore(
(state) => state.setFolderIdDragging, (state) => state.setFolderIdDragging
); );
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
@ -45,7 +45,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
| React.DragEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement>
| React.DragEvent<HTMLButtonElement> | React.DragEvent<HTMLButtonElement>
| React.DragEvent<HTMLAnchorElement>, | React.DragEvent<HTMLAnchorElement>,
folderId: string, folderId: string
) => { ) => {
e.preventDefault(); e.preventDefault();
@ -60,7 +60,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
| React.DragEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement>
| React.DragEvent<HTMLButtonElement> | React.DragEvent<HTMLButtonElement>
| React.DragEvent<HTMLAnchorElement>, | React.DragEvent<HTMLAnchorElement>,
folderId: string, folderId: string
) => { ) => {
if (e.dataTransfer.types.some((types) => types === "Files")) { if (e.dataTransfer.types.some((types) => types === "Files")) {
setFolderDragging(true); setFolderDragging(true);
@ -73,7 +73,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
e: e:
| React.DragEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement>
| React.DragEvent<HTMLButtonElement> | React.DragEvent<HTMLButtonElement>
| React.DragEvent<HTMLAnchorElement>, | React.DragEvent<HTMLAnchorElement>
) => { ) => {
e.preventDefault(); e.preventDefault();
if (e.target === e.currentTarget) { if (e.target === e.currentTarget) {
@ -87,7 +87,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
| React.DragEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement>
| React.DragEvent<HTMLButtonElement> | React.DragEvent<HTMLButtonElement>
| React.DragEvent<HTMLAnchorElement>, | React.DragEvent<HTMLAnchorElement>,
folderId: string, folderId: string
) => { ) => {
if (e?.dataTransfer?.getData("flow")) { if (e?.dataTransfer?.getData("flow")) {
const data = JSON.parse(e?.dataTransfer?.getData("flow")); const data = JSON.parse(e?.dataTransfer?.getData("flow"));

View file

@ -5,9 +5,6 @@ import { cn } from "../../utils/utils";
import HorizontalScrollFadeComponent from "../horizontalScrollFadeComponent"; import HorizontalScrollFadeComponent from "../horizontalScrollFadeComponent";
import SideBarButtonsComponent from "./components/sideBarButtons"; import SideBarButtonsComponent from "./components/sideBarButtons";
import SideBarFoldersButtonsComponent from "./components/sideBarFolderButtons"; import SideBarFoldersButtonsComponent from "./components/sideBarFolderButtons";
import { addFolder } from "../../pages/MainPage/services";
import { useNavigate } from "react-router-dom";
import useFlowStore from "../../stores/flowStore";
type SidebarNavProps = { type SidebarNavProps = {
items: { items: {

View file

@ -1,6 +1,4 @@
import { cn } from "../../../../utils/utils"; import { cn } from "../../../../utils/utils";
import ShadTooltip from "../../../shadTooltipComponent";
import { Toggle } from "../../../ui/toggle";
export default function ResetColumns({ export default function ResetColumns({
resetGrid, resetGrid,
@ -8,15 +6,6 @@ export default function ResetColumns({
resetGrid: () => void; resetGrid: () => void;
}): JSX.Element { }): JSX.Element {
return ( return (
/*<div className="absolute left-2 bottom-1 cursor-pointer">
<div
className="flex h-10 items-center justify-center px-2 pl-3 rounded-md border border-ring/60 text-sm text-[#bccadc] ring-offset-background placeholder:text-muted-foreground hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
onClick={() => setShow(!show)}
>
<ForwardedIconComponent name="Settings"></ForwardedIconComponent>
<ForwardedIconComponent name={show ? "ChevronLeft" : "ChevronRight"} className="transition-all"></ForwardedIconComponent>
</div>
</div>*/
<div className={cn("absolute bottom-4 left-6")}> <div className={cn("absolute bottom-4 left-6")}>
<span <span
className="cursor-pointer underline" className="cursor-pointer underline"

View file

@ -1,11 +1,11 @@
import { CustomCellRendererProps } from "ag-grid-react"; import { CustomCellRendererProps } from "ag-grid-react";
import { cn, isTimeStampString } from "../../utils/utils"; import { cn, isTimeStampString } from "../../../../utils/utils";
import ArrayReader from "../arrayReaderComponent"; import ArrayReader from "../../../arrayReaderComponent";
import DateReader from "../dateReaderComponent"; import DateReader from "../../../dateReaderComponent";
import NumberReader from "../numberReader"; import NumberReader from "../../../numberReader";
import ObjectRender from "../objectRender"; import ObjectRender from "../../../objectRender";
import StringReader from "../stringReaderComponent"; import StringReader from "../../../stringReaderComponent";
import { Badge } from "../ui/badge"; import { Badge } from "../../../ui/badge";
export default function TableAutoCellRender({ export default function TableAutoCellRender({
value, value,
@ -43,7 +43,6 @@ export default function TableAutoCellRender({
} else { } else {
return <StringReader string={value} />; return <StringReader string={value} />;
} }
break;
case "number": case "number":
return <NumberReader number={value} />; return <NumberReader number={value} />;
default: default:

View file

@ -0,0 +1,266 @@
import { CustomCellRendererProps } from "ag-grid-react";
import { cloneDeep } from "lodash";
import { useState } from "react";
import CodeAreaComponent from "../../../codeAreaComponent";
import DictComponent from "../../../dictComponent";
import Dropdown from "../../../dropdownComponent";
import FloatComponent from "../../../floatComponent";
import InputFileComponent from "../../../inputFileComponent";
import InputGlobalComponent from "../../../inputGlobalComponent";
import InputListComponent from "../../../inputListComponent";
import IntComponent from "../../../intComponent";
import KeypairListComponent from "../../../keypairListComponent";
import PromptAreaComponent from "../../../promptComponent";
import TextAreaComponent from "../../../textAreaComponent";
import ToggleShadComponent from "../../../toggleShadComponent";
import useFlowStore from "../../../../stores/flowStore";
import {
convertObjToArray,
convertValuesToNumbers,
hasDuplicateKeys,
scapedJSONStringfy,
} from "../../../../utils/reactflowUtils";
import { classNames } from "../../../../utils/utils";
export default function TableNodeCellRender({
node: { data },
value: {
value,
nodeClass,
handleOnNewValue: handleOnNewValueNode,
handleOnChangeDb,
},
}: CustomCellRendererProps) {
const handleOnNewValue = (newValue: any, name: string) => {
handleOnNewValueNode(newValue, name);
setTemplateData((old) => {
let newData = cloneDeep(old);
newData.value = newValue;
return newData;
});
setTemplateValue(newValue);
};
const [templateValue, setTemplateValue] = useState(value);
const [templateData, setTemplateData] = useState(data);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
const edges = useFlowStore((state) => state.edges);
const id = {
inputTypes: templateData.input_types,
type: templateData.type,
id: nodeClass.id,
fieldName: templateData.key,
};
const disabled =
edges.some(
(edge) =>
edge.targetHandle ===
scapedJSONStringfy(
templateData.proxy
? {
...id,
proxy: templateData.proxy,
}
: id,
),
) ?? false;
function getCellType() {
switch (templateData.type) {
case "str":
if (!templateData.options) {
return templateData?.list ? (
<InputListComponent
componentName={templateData.key ?? undefined}
editNode={true}
disabled={disabled}
value={
!templateValue || templateValue === "" ? [""] : templateValue
}
onChange={(value: string[]) => {
handleOnNewValue(value, templateData.key);
}}
/>
) : templateData.multiline ? (
<TextAreaComponent
id={"textarea-edit-" + templateData.name}
data-testid={"textarea-edit-" + templateData.name}
disabled={disabled}
editNode={true}
value={templateValue ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
/>
) : (
<InputGlobalComponent
disabled={disabled}
editNode={true}
onChange={(value) => handleOnNewValue(value, templateData.key)}
setDb={(value) => {
handleOnChangeDb(value, templateData.key);
}}
name={templateData.key}
data={templateData}
/>
);
} else {
return (
<Dropdown
editNode={true}
options={templateData.options}
onSelect={(value) => handleOnNewValue(value, templateData.key)}
value={templateValue ?? "Choose an option"}
id={"dropdown-edit-" + templateData.name}
/>
);
}
case "NestedDict":
return (
<DictComponent
disabled={disabled}
editNode={true}
value={templateValue.toString() === "{}" ? {} : templateValue}
onChange={(newValue) => {
handleOnNewValue(newValue, templateData.key);
}}
id="editnode-div-dict-input"
/>
);
case "dict":
return (
<div
className={classNames(
"max-h-48 w-full overflow-auto custom-scroll",
templateValue?.length > 1 ? "my-3" : "",
)}
>
<KeypairListComponent
disabled={disabled}
editNode={true}
value={
templateValue?.length === 0 || !templateValue
? [{ "": "" }]
: convertObjToArray(templateValue, templateData.type)
}
duplicateKey={errorDuplicateKey}
onChange={(newValue) => {
const valueToNumbers = convertValuesToNumbers(newValue);
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
handleOnNewValue(valueToNumbers, templateData.key);
}}
isList={templateData.list ?? false}
/>
</div>
);
case "bool":
return (
<ToggleShadComponent
id={"toggle-edit-" + templateData.name}
disabled={disabled}
enabled={templateValue}
setEnabled={(isEnabled) => {
handleOnNewValue(isEnabled, templateData.key);
}}
size="small"
editNode={true}
/>
);
case "float":
return (
<FloatComponent
disabled={disabled}
editNode={true}
rangeSpec={templateData.rangeSpec}
value={templateValue ?? ""}
onChange={(value) => {
handleOnNewValue(value, templateData.key);
}}
/>
);
case "int":
return (
<IntComponent
rangeSpec={templateData.rangeSpec}
id={"edit-int-input-" + templateData.name}
disabled={disabled}
editNode={true}
value={templateValue ?? ""}
onChange={(value) => {
handleOnNewValue(value, templateData.key);
}}
/>
);
case "file":
return (
<InputFileComponent
editNode={true}
disabled={disabled}
value={templateValue ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
fileTypes={templateData.fileTypes}
onFileChange={(filePath: string) => {
templateData.file_path = filePath;
}}
/>
);
case "prompt":
return (
<PromptAreaComponent
readonly={nodeClass.flow ? true : false}
field_name={templateData.key}
editNode={true}
disabled={disabled}
nodeClass={nodeClass}
setNodeClass={(value) => {
nodeClass = value;
}}
value={templateValue ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
id={"prompt-area-edit-" + templateData.name}
data-testid={"modal-prompt-input-" + templateData.name}
/>
);
case "code":
return (
<CodeAreaComponent
readonly={nodeClass.flow && templateData.dynamic ? true : false}
dynamic={templateData.dynamic ?? false}
setNodeClass={(value) => {
nodeClass = value;
}}
nodeClass={nodeClass}
disabled={disabled}
editNode={true}
value={templateValue ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
id={"code-area-edit" + templateData.name}
/>
);
case "Any":
return <>-</>;
default:
return String(templateValue);
}
}
return (
<div className="group flex h-full w-[300px] items-center justify-center py-2.5">
{getCellType()}
</div>
);
}

View file

@ -0,0 +1,24 @@
import { CustomCellRendererProps } from "ag-grid-react";
import { useState } from "react";
import ToggleShadComponent from "../../../toggleShadComponent";
export default function TableToggleCellRender({
value: { name, enabled, setEnabled },
}: CustomCellRendererProps) {
const [value, setValue] = useState(enabled);
return (
<div className="flex h-full items-center">
<ToggleShadComponent
id={"show" + name}
enabled={value}
setEnabled={(e) => {
setValue(e);
setEnabled(e);
}}
size="small"
editNode={true}
/>
</div>
);
}

View file

@ -0,0 +1,9 @@
import { CustomTooltipProps } from "ag-grid-react";
export default function TableTooltipRender({ value }: CustomTooltipProps) {
return (
<div className="z-45 overflow-y-auto rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1">
{value}
</div>
);
}

View file

@ -1,7 +1,7 @@
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
import "ag-grid-community/styles/ag-theme-quartz.css"; // Optional Theme applied to the grid import "ag-grid-community/styles/ag-theme-quartz.css"; // Optional Theme applied to the grid
import { AgGridReact, AgGridReactProps } from "ag-grid-react"; import { AgGridReact, AgGridReactProps } from "ag-grid-react";
import { ElementRef, forwardRef, useEffect, useRef } from "react"; import { ElementRef, forwardRef, useRef } from "react";
import { import {
DEFAULT_TABLE_ALERT_MSG, DEFAULT_TABLE_ALERT_MSG,
DEFAULT_TABLE_ALERT_TITLE, DEFAULT_TABLE_ALERT_TITLE,
@ -11,10 +11,8 @@ import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid
import { cn, toTitleCase } from "../../utils/utils"; import { cn, toTitleCase } from "../../utils/utils";
import ForwardedIconComponent from "../genericIconComponent"; import ForwardedIconComponent from "../genericIconComponent";
import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; import { Alert, AlertDescription, AlertTitle } from "../ui/alert";
import { Toggle } from "../ui/toggle";
import ShadTooltip from "../shadTooltipComponent";
import resetGrid from "./utils/reset-grid-columns";
import ResetColumns from "./components/ResetColumns"; import ResetColumns from "./components/ResetColumns";
import resetGrid from "./utils/reset-grid-columns";
interface TableComponentProps extends AgGridReactProps { interface TableComponentProps extends AgGridReactProps {
columnDefs: NonNullable<AgGridReactProps["columnDefs"]>; columnDefs: NonNullable<AgGridReactProps["columnDefs"]>;
@ -34,7 +32,7 @@ const TableComponent = forwardRef<
alertDescription = DEFAULT_TABLE_ALERT_MSG, alertDescription = DEFAULT_TABLE_ALERT_MSG,
...props ...props
}, },
ref, ref
) => { ) => {
let colDef = props.columnDefs.map((col, index) => { let colDef = props.columnDefs.map((col, index) => {
let newCol = { let newCol = {
@ -91,7 +89,7 @@ const TableComponent = forwardRef<
const onColumnMoved = (params) => { const onColumnMoved = (params) => {
const updatedColumnDefs = makeLastColumnNonResizable( const updatedColumnDefs = makeLastColumnNonResizable(
params.columnApi.getAllGridColumns().map((col) => col.getColDef()), params.columnApi.getAllGridColumns().map((col) => col.getColDef())
); );
params.api.setColumnDefs(updatedColumnDefs); params.api.setColumnDefs(updatedColumnDefs);
if (props.onColumnMoved) props.onColumnMoved(params); if (props.onColumnMoved) props.onColumnMoved(params);
@ -116,7 +114,7 @@ const TableComponent = forwardRef<
className={cn( className={cn(
dark ? "ag-theme-quartz-dark" : "ag-theme-quartz", dark ? "ag-theme-quartz-dark" : "ag-theme-quartz",
"ag-theme-shadcn flex h-full flex-col", "ag-theme-shadcn flex h-full flex-col",
"relative", "relative"
)} // applying the grid theme )} // applying the grid theme
> >
<AgGridReact <AgGridReact
@ -126,9 +124,11 @@ const TableComponent = forwardRef<
minWidth: 100, minWidth: 100,
autoHeight: true, autoHeight: true,
}} }}
tooltipInteraction={true}
columnDefs={colDef} columnDefs={colDef}
ref={realRef} ref={realRef}
getRowId={(params) => {
return params.data.id;
}}
pagination={true} pagination={true}
onGridReady={onGridReady} onGridReady={onGridReady}
onColumnMoved={onColumnMoved} onColumnMoved={onColumnMoved}
@ -136,7 +136,7 @@ const TableComponent = forwardRef<
<ResetColumns resetGrid={() => resetGrid(realRef, initialColumnDefs)} /> <ResetColumns resetGrid={() => resetGrid(realRef, initialColumnDefs)} />
</div> </div>
); );
}, }
); );
export default TableComponent; export default TableComponent;

View file

@ -29,7 +29,6 @@ export default function ToggleShadComponent({
} }
return ( return (
<div className={disabled ? "pointer-events-none cursor-not-allowed " : ""}>
<Switch <Switch
id={id} id={id}
data-testid={id} data-testid={id}
@ -43,6 +42,5 @@ export default function ToggleShadComponent({
setEnabled(isEnabled); setEnabled(isEnabled);
}} }}
></Switch> ></Switch>
</div>
); );
} }

View file

@ -34,7 +34,7 @@ const AccordionTrigger = React.forwardRef<
<div <div
className={cn( className={cn(
"flex flex-1 cursor-pointer items-center justify-between py-4 text-sm font-medium transition-all [&[data-state=open]>svg]:rotate-180", "flex flex-1 cursor-pointer items-center justify-between py-4 text-sm font-medium transition-all [&[data-state=open]>svg]:rotate-180",
className, className
)} )}
> >
{children} {children}
@ -46,7 +46,7 @@ const AccordionTrigger = React.forwardRef<
<ChevronDownIcon <ChevronDownIcon
className={cn( className={cn(
"h-4 w-4 font-bold transition-transform duration-200", "h-4 w-4 font-bold transition-transform duration-200",
disabled ? "text-muted-foreground" : "text-primary", disabled ? "text-muted-foreground" : "text-primary"
)} )}
/> />
</ShadTooltip> </ShadTooltip>
@ -64,7 +64,7 @@ const AccordionContent = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm", "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm",
className, className
)} )}
{...props} {...props}
> >

View file

@ -35,7 +35,7 @@ const buttonVariants = cva(
variant: "default", variant: "default",
size: "default", size: "default",
}, },
}, }
); );
export interface ButtonProps export interface ButtonProps
@ -59,12 +59,13 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
variant, variant,
size, size,
loading, loading,
type,
disabled, disabled,
asChild = false, asChild = false,
children, children,
...props ...props
}, },
ref, ref
) => { ) => {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : "button";
let newChildren = children; let newChildren = children;
@ -76,6 +77,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
<Comp <Comp
className={cn(buttonVariants({ variant, size, className }))} className={cn(buttonVariants({ variant, size, className }))}
disabled={loading || disabled} disabled={loading || disabled}
{...(asChild ? {} : { type: type || "button" })}
ref={ref} ref={ref}
{...props} {...props}
> >
@ -95,7 +97,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
</Comp> </Comp>
</> </>
); );
}, }
); );
Button.displayName = "Button"; Button.displayName = "Button";

View file

@ -9,7 +9,7 @@ const Card = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"flex flex-col justify-between rounded-lg border bg-muted text-card-foreground shadow-sm transition-all", "flex flex-col justify-between rounded-lg border bg-muted text-card-foreground shadow-sm transition-all",
className, className
)} )}
{...props} {...props}
/> />
@ -36,7 +36,7 @@ const CardTitle = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"text-base font-semibold leading-tight tracking-tight", "text-base font-semibold leading-tight tracking-tight",
className, className
)} )}
{...props} {...props}
/> />

View file

@ -31,11 +31,7 @@ function RefreshButton({
// icon class name should take into account the disabled state and the loading state // icon class name should take into account the disabled state and the loading state
const disabledIconTextClass = disabled ? "text-muted-foreground" : ""; const disabledIconTextClass = disabled ? "text-muted-foreground" : "";
const iconClassName = cn( const iconClassName = cn("h-4 w-4 animate-wiggle", disabledIconTextClass);
"h-4 w-4",
isLoading ? "animate-spin" : "animate-wiggle",
disabledIconTextClass
);
return ( return (
<Button <Button
@ -44,10 +40,11 @@ function RefreshButton({
className={classNames} className={classNames}
onClick={handleClick} onClick={handleClick}
id={id} id={id}
loading={isLoading}
> >
{button_text && <span className="mr-1">{button_text}</span>} {button_text && <span className="mr-1">{button_text}</span>}
<IconComponent <IconComponent
name={isLoading ? "Loader2" : "RefreshCcw"} name={"RefreshCcw"}
className={iconClassName} className={iconClassName}
id={id + "-icon"} id={id + "-icon"}
/> />

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import * as React from "react";
import * as TogglePrimitive from "@radix-ui/react-toggle"; import * as TogglePrimitive from "@radix-ui/react-toggle";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
@ -25,7 +25,7 @@ const toggleVariants = cva(
variant: "default", variant: "default",
size: "default", size: "default",
}, },
}, }
); );
const Toggle = React.forwardRef< const Toggle = React.forwardRef<

View file

@ -20,7 +20,7 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-45 overflow-y-auto rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1", "z-45 overflow-y-auto rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1",
className, className
)} )}
{...props} {...props}
/> />
@ -37,7 +37,7 @@ const TooltipContentWithoutPortal = React.forwardRef<
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-45 overflow-y-auto rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1", "z-45 overflow-y-auto rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1",
className, className
)} )}
{...props} {...props}
/> />

View file

@ -23,6 +23,7 @@ export const USER_EDIT_ERROR_ALERT = "Error on edit user";
export const USER_ADD_ERROR_ALERT = "Error when adding new user"; export const USER_ADD_ERROR_ALERT = "Error when adding new user";
export const SIGNIN_ERROR_ALERT = "Error signing in"; export const SIGNIN_ERROR_ALERT = "Error signing in";
export const DEL_KEY_ERROR_ALERT = "Error on delete key"; export const DEL_KEY_ERROR_ALERT = "Error on delete key";
export const DEL_KEY_ERROR_ALERT_PLURAL = "Error on delete keys";
export const UPLOAD_ERROR_ALERT = "Error uploading file"; export const UPLOAD_ERROR_ALERT = "Error uploading file";
export const WRONG_FILE_ERROR_ALERT = "Invalid file type"; export const WRONG_FILE_ERROR_ALERT = "Invalid file type";
export const UPLOAD_ALERT_LIST = "Please upload a JSON file"; export const UPLOAD_ALERT_LIST = "Please upload a JSON file";
@ -54,6 +55,7 @@ export const USER_DEL_SUCCESS_ALERT = "Success! User deleted!";
export const USER_EDIT_SUCCESS_ALERT = "Success! User edited!"; export const USER_EDIT_SUCCESS_ALERT = "Success! User edited!";
export const USER_ADD_SUCCESS_ALERT = "Success! New user added!"; export const USER_ADD_SUCCESS_ALERT = "Success! New user added!";
export const DEL_KEY_SUCCESS_ALERT = "Success! Key deleted!"; export const DEL_KEY_SUCCESS_ALERT = "Success! Key deleted!";
export const DEL_KEY_SUCCESS_ALERT_PLURAL = "Success! Keys deleted!";
export const FLOW_BUILD_SUCCESS_ALERT = `Flow built successfully`; export const FLOW_BUILD_SUCCESS_ALERT = `Flow built successfully`;
export const SAVE_SUCCESS_ALERT = "Changes saved successfully!"; export const SAVE_SUCCESS_ALERT = "Changes saved successfully!";

View file

@ -613,11 +613,8 @@ export const FETCH_ERROR_DESCRIPION =
export const SIGN_UP_SUCCESS = "Account created! Await admin activation. "; export const SIGN_UP_SUCCESS = "Account created! Await admin activation. ";
export const API_PAGE_PARAGRAPH_1 = export const API_PAGE_PARAGRAPH =
"Your secret API keys are listed below. Please note that we do not display your secret API keys again after you generate them."; "Your secret API keys are listed below. Do not share your API key with others, or expose it in the browser or other client-side code.";
export const API_PAGE_PARAGRAPH_2 =
"Do not share your API key with others, or expose it in the browser or other client-side code.";
export const API_PAGE_USER_KEYS = export const API_PAGE_USER_KEYS =
"This user does not have any keys assigned at the moment."; "This user does not have any keys assigned at the moment.";

View file

@ -8,7 +8,7 @@ export function checkDuplicateRequestAndStoreRequest(config) {
const currentTime = Date.now(); const currentTime = Date.now();
const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) =>
config?.url!.includes(request), config?.url!.includes(request)
); );
if ( if (

View file

@ -17,6 +17,7 @@ import {
} from "../../types/api/index"; } from "../../types/api/index";
import { UserInputType } from "../../types/components"; import { UserInputType } from "../../types/components";
import { FlowStyleType, FlowType } from "../../types/flow"; import { FlowStyleType, FlowType } from "../../types/flow";
import { Message } from "../../types/messages";
import { StoreComponentResponse } from "../../types/store"; import { StoreComponentResponse } from "../../types/store";
import { FlowPoolType } from "../../types/zustand/flow"; import { FlowPoolType } from "../../types/zustand/flow";
import { extractColumnsFromRows } from "../../utils/utils"; import { extractColumnsFromRows } from "../../utils/utils";
@ -28,7 +29,6 @@ import {
UploadFileTypeAPI, UploadFileTypeAPI,
errorsTypeAPI, errorsTypeAPI,
} from "./../../types/api/index"; } from "./../../types/api/index";
import { Message } from "../../types/messages";
/** /**
* Fetches all objects from the API endpoint. * Fetches all objects from the API endpoint.
@ -62,7 +62,7 @@ export async function sendAll(data: sendAllProps) {
} }
export async function postValidateCode( export async function postValidateCode(
code: string, code: string
): Promise<AxiosResponse<errorsTypeAPI>> { ): Promise<AxiosResponse<errorsTypeAPI>> {
return await api.post(`${BASE_URL_API}validate/code`, { code }); return await api.post(`${BASE_URL_API}validate/code`, { code });
} }
@ -77,7 +77,7 @@ export async function postValidateCode(
export async function postValidatePrompt( export async function postValidatePrompt(
name: string, name: string,
template: string, template: string,
frontend_node: APIClassType, frontend_node: APIClassType
): Promise<AxiosResponse<PromptTypeAPI>> { ): Promise<AxiosResponse<PromptTypeAPI>> {
return api.post(`${BASE_URL_API}validate/prompt`, { return api.post(`${BASE_URL_API}validate/prompt`, {
name, name,
@ -150,7 +150,7 @@ export async function saveFlowToDatabase(newFlow: {
* @throws Will throw an error if the update fails. * @throws Will throw an error if the update fails.
*/ */
export async function updateFlowInDatabase( export async function updateFlowInDatabase(
updatedFlow: FlowType, updatedFlow: FlowType
): Promise<FlowType> { ): Promise<FlowType> {
try { try {
const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, { const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, {
@ -328,7 +328,7 @@ export async function getHealth() {
* *
*/ */
export async function getBuildStatus( export async function getBuildStatus(
flowId: string, flowId: string
): Promise<AxiosResponse<BuildStatusTypeAPI>> { ): Promise<AxiosResponse<BuildStatusTypeAPI>> {
return await api.get(`${BASE_URL_API}build/${flowId}/status`); return await api.get(`${BASE_URL_API}build/${flowId}/status`);
} }
@ -341,7 +341,7 @@ export async function getBuildStatus(
* *
*/ */
export async function postBuildInit( export async function postBuildInit(
flow: FlowType, flow: FlowType
): Promise<AxiosResponse<InitTypeAPI>> { ): Promise<AxiosResponse<InitTypeAPI>> {
return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow); return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow);
} }
@ -357,7 +357,7 @@ export async function postBuildInit(
*/ */
export async function uploadFile( export async function uploadFile(
file: File, file: File,
id: string, id: string
): Promise<AxiosResponse<UploadFileTypeAPI>> { ): Promise<AxiosResponse<UploadFileTypeAPI>> {
const formData = new FormData(); const formData = new FormData();
formData.append("file", file); formData.append("file", file);
@ -366,7 +366,7 @@ export async function uploadFile(
export async function postCustomComponent( export async function postCustomComponent(
code: string, code: string,
apiClass: APIClassType, apiClass: APIClassType
): Promise<AxiosResponse<APIClassType>> { ): Promise<AxiosResponse<APIClassType>> {
// let template = apiClass.template; // let template = apiClass.template;
return await api.post(`${BASE_URL_API}custom_component`, { return await api.post(`${BASE_URL_API}custom_component`, {
@ -379,7 +379,7 @@ export async function postCustomComponentUpdate(
code: string, code: string,
template: APITemplateType, template: APITemplateType,
field: string, field: string,
field_value: any, field_value: any
): Promise<AxiosResponse<APIClassType>> { ): Promise<AxiosResponse<APIClassType>> {
return await api.post(`${BASE_URL_API}custom_component/update`, { return await api.post(`${BASE_URL_API}custom_component/update`, {
code, code,
@ -401,7 +401,7 @@ export async function onLogin(user: LoginType) {
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
}, },
}, }
); );
if (response.status === 200) { if (response.status === 200) {
@ -463,11 +463,11 @@ export async function addUser(user: UserInputType): Promise<Array<Users>> {
export async function getUsersPage( export async function getUsersPage(
skip: number, skip: number,
limit: number, limit: number
): Promise<Array<Users>> { ): Promise<Array<Users>> {
try { try {
const res = await api.get( const res = await api.get(
`${BASE_URL_API}users/?skip=${skip}&limit=${limit}`, `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`
); );
if (res.status === 200) { if (res.status === 200) {
return res.data; return res.data;
@ -504,7 +504,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) {
try { try {
const res = await api.patch( const res = await api.patch(
`${BASE_URL_API}users/${user_id}/reset-password`, `${BASE_URL_API}users/${user_id}/reset-password`,
user, user
); );
if (res.status === 200) { if (res.status === 200) {
return res.data; return res.data;
@ -578,7 +578,7 @@ export async function saveFlowStore(
last_tested_version?: string; last_tested_version?: string;
}, },
tags: string[], tags: string[],
publicFlow = false, publicFlow = false
): Promise<FlowType> { ): Promise<FlowType> {
try { try {
const response = await api.post(`${BASE_URL_API}store/components/`, { const response = await api.post(`${BASE_URL_API}store/components/`, {
@ -707,7 +707,7 @@ export async function postStoreComponents(component: Component) {
export async function getComponent(component_id: string) { export async function getComponent(component_id: string) {
try { try {
const res = await api.get( const res = await api.get(
`${BASE_URL_API}store/components/${component_id}`, `${BASE_URL_API}store/components/${component_id}`
); );
if (res.status === 200) { if (res.status === 200) {
return res.data; return res.data;
@ -722,7 +722,7 @@ export async function searchComponent(
page?: number | null, page?: number | null,
limit?: number | null, limit?: number | null,
status?: string | null, status?: string | null,
tags?: string[], tags?: string[]
): Promise<StoreComponentResponse | undefined> { ): Promise<StoreComponentResponse | undefined> {
try { try {
let url = `${BASE_URL_API}store/components/`; let url = `${BASE_URL_API}store/components/`;
@ -834,7 +834,7 @@ export async function updateFlowStore(
}, },
tags: string[], tags: string[],
publicFlow = false, publicFlow = false,
id: string, id: string
): Promise<FlowType> { ): Promise<FlowType> {
try { try {
const response = await api.patch(`${BASE_URL_API}store/components/${id}`, { const response = await api.patch(`${BASE_URL_API}store/components/${id}`, {
@ -918,7 +918,7 @@ export async function deleteGlobalVariable(id: string) {
export async function updateGlobalVariable( export async function updateGlobalVariable(
name: string, name: string,
value: string, value: string,
id: string, id: string
) { ) {
try { try {
const response = api.patch(`${BASE_URL_API}variables/${id}`, { const response = api.patch(`${BASE_URL_API}variables/${id}`, {
@ -937,7 +937,7 @@ export async function getVerticesOrder(
startNodeId?: string | null, startNodeId?: string | null,
stopNodeId?: string | null, stopNodeId?: string | null,
nodes?: Node[], nodes?: Node[],
Edges?: Edge[], Edges?: Edge[]
): Promise<AxiosResponse<VerticesOrderTypeAPI>> { ): Promise<AxiosResponse<VerticesOrderTypeAPI>> {
// nodeId is optional and is a query parameter // nodeId is optional and is a query parameter
// if nodeId is not provided, the API will return all vertices // if nodeId is not provided, the API will return all vertices
@ -957,7 +957,7 @@ export async function getVerticesOrder(
return await api.post( return await api.post(
`${BASE_URL_API}build/${flowId}/vertices`, `${BASE_URL_API}build/${flowId}/vertices`,
data, data,
config, config
); );
} }
@ -965,7 +965,7 @@ export async function postBuildVertex(
flowId: string, flowId: string,
vertexId: string, vertexId: string,
input_value: string, input_value: string,
files?: string[], files?: string[]
): Promise<AxiosResponse<VertexBuildTypeAPI>> { ): Promise<AxiosResponse<VertexBuildTypeAPI>> {
// input_value is optional and is a query parameter // input_value is optional and is a query parameter
const data = input_value const data = input_value
@ -976,7 +976,7 @@ export async function postBuildVertex(
} }
return await api.post( return await api.post(
`${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, `${BASE_URL_API}build/${flowId}/vertices/${vertexId}`,
data, data
); );
} }
@ -1000,7 +1000,7 @@ export async function getFlowPool({
} }
export async function deleteFlowPool( export async function deleteFlowPool(
flowId: string, flowId: string
): Promise<AxiosResponse<any>> { ): Promise<AxiosResponse<any>> {
const config = {}; const config = {};
config["params"] = { flow_id: flowId }; config["params"] = { flow_id: flowId };
@ -1014,7 +1014,7 @@ export async function deleteFlowPool(
* @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses. * @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses.
*/ */
export async function multipleDeleteFlowsComponents( export async function multipleDeleteFlowsComponents(
flowIds: string[], flowIds: string[]
): Promise<AxiosResponse<any>[]> { ): Promise<AxiosResponse<any>[]> {
const batches: string[][] = []; const batches: string[][] = [];
@ -1037,7 +1037,7 @@ export async function multipleDeleteFlowsComponents(
// Execute all delete requests // Execute all delete requests
const responses: Promise<AxiosResponse<any>>[] = batches.map((batch) => const responses: Promise<AxiosResponse<any>>[] = batches.map((batch) =>
deleteBatch(batch), deleteBatch(batch)
); );
// Return the responses after all requests are completed // Return the responses after all requests are completed
@ -1047,7 +1047,7 @@ export async function multipleDeleteFlowsComponents(
export async function getTransactionTable( export async function getTransactionTable(
id: string, id: string,
mode: "intersection" | "union", mode: "intersection" | "union",
params = {}, params = {}
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> { ): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> {
const config = {}; const config = {};
config["params"] = { flow_id: id }; config["params"] = { flow_id: id };
@ -1063,7 +1063,7 @@ export async function getMessagesTable(
mode: "intersection" | "union", mode: "intersection" | "union",
id?: string, id?: string,
excludedFields?: string[], excludedFields?: string[],
params = {}, params = {}
): Promise<{ rows: Array<Message>; columns: Array<ColDef | ColGroupDef> }> { ): Promise<{ rows: Array<Message>; columns: Array<ColDef | ColGroupDef> }> {
const config = {}; const config = {};
if (id) { if (id) {

View file

@ -98,7 +98,7 @@ export default function ParameterComponent({
debouncedHandleUpdateValues, debouncedHandleUpdateValues,
setNode, setNode,
renderTooltips, renderTooltips,
setIsLoading, setIsLoading
); );
const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass( const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass(
@ -107,7 +107,7 @@ export default function ParameterComponent({
takeSnapshot, takeSnapshot,
setNode, setNode,
updateNodeInternals, updateNodeInternals,
renderTooltips, renderTooltips
); );
const { handleRefreshButtonPress: handleRefreshButtonPressHook } = const { handleRefreshButtonPress: handleRefreshButtonPressHook } =
@ -116,7 +116,7 @@ export default function ParameterComponent({
let disabled = let disabled =
edges.some( edges.some(
(edge) => (edge) =>
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id), edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id)
) ?? false; ) ?? false;
const handleRefreshButtonPress = async (name, data) => { const handleRefreshButtonPress = async (name, data) => {
@ -129,12 +129,12 @@ export default function ParameterComponent({
handleUpdateValues, handleUpdateValues,
setNode, setNode,
renderTooltips, renderTooltips,
setIsLoading, setIsLoading
); );
const handleOnNewValue = async ( const handleOnNewValue = async (
newValue: string | string[] | boolean | Object[], newValue: string | string[] | boolean | Object[],
skipSnapshot: boolean | undefined = false, skipSnapshot: boolean | undefined = false
): Promise<void> => { ): Promise<void> => {
handleOnNewValueHook(newValue, skipSnapshot); handleOnNewValueHook(newValue, skipSnapshot);
}; };
@ -216,7 +216,7 @@ export default function ParameterComponent({
className={classNames( className={classNames(
left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ", left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ",
"h-3 w-3 rounded-full border-2 bg-background", "h-3 w-3 rounded-full border-2 bg-background",
!showNode ? "mt-0" : "", !showNode ? "mt-0" : ""
)} )}
style={{ style={{
borderColor: color ?? nodeColors.unknown, borderColor: color ?? nodeColors.unknown,
@ -334,7 +334,7 @@ export default function ParameterComponent({
} }
className={classNames( className={classNames(
left ? "-ml-0.5" : "-mr-0.5", left ? "-ml-0.5" : "-mr-0.5",
"h-3 w-3 rounded-full border-2 bg-background", "h-3 w-3 rounded-full border-2 bg-background"
)} )}
style={{ borderColor: color ?? nodeColors.unknown }} style={{ borderColor: color ?? nodeColors.unknown }}
onClick={() => setFilterEdge(groupedEdge.current)} onClick={() => setFilterEdge(groupedEdge.current)}
@ -430,7 +430,7 @@ export default function ParameterComponent({
}); });
}} }}
name={name} name={name}
data={data} data={data.node?.template[name]}
/> />
</div> </div>
{data.node?.template[name]?.refresh_button && ( {data.node?.template[name]?.refresh_button && (
@ -486,8 +486,8 @@ export default function ParameterComponent({
data.node?.template[name]?.real_time_refresh) data.node?.template[name]?.real_time_refresh)
} }
> >
<div className="mt-2 flex w-full items-center"> <div className="mt-2 flex w-full items-center gap-2">
<div className="w-5/6 flex-grow"> <div className="flex-1">
<Dropdown <Dropdown
disabled={disabled} disabled={disabled}
isLoading={isLoading} isLoading={isLoading}
@ -505,7 +505,6 @@ export default function ParameterComponent({
name={name} name={name}
data={data} data={data}
button_text={data.node?.template[name]?.refresh_button_text} button_text={data.node?.template[name]?.refresh_button_text}
className="extra-side-bar-buttons ml-2 mt-1"
handleUpdateValues={handleRefreshButtonPress} handleUpdateValues={handleRefreshButtonPress}
id={"refresh-button-" + name} id={"refresh-button-" + name}
/> />

View file

@ -54,10 +54,10 @@ export default function GenericNode({
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const isDark = useDarkStore((state) => state.dark); const isDark = useDarkStore((state) => state.dark);
const buildStatus = useFlowStore( const buildStatus = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.status, (state) => state.flowBuildStatus[data.id]?.status
); );
const lastRunTime = useFlowStore( const lastRunTime = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.timestamp, (state) => state.flowBuildStatus[data.id]?.timestamp
); );
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
@ -65,7 +65,7 @@ export default function GenericNode({
const [nodeName, setNodeName] = useState(data.node!.display_name); const [nodeName, setNodeName] = useState(data.node!.display_name);
const [inputDescription, setInputDescription] = useState(false); const [inputDescription, setInputDescription] = useState(false);
const [nodeDescription, setNodeDescription] = useState( const [nodeDescription, setNodeDescription] = useState(
data.node?.description!, data.node?.description!
); );
const [isOutdated, setIsOutdated] = useState(false); const [isOutdated, setIsOutdated] = useState(false);
const [validationStatus, setValidationStatus] = const [validationStatus, setValidationStatus] =
@ -83,7 +83,7 @@ export default function GenericNode({
data.node!, data.node!,
setNode, setNode,
setIsOutdated, setIsOutdated,
updateNodeInternals, updateNodeInternals
); );
const name = nodeIconsLucide[data.type] ? data.type : types[data.type]; const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
@ -114,12 +114,12 @@ export default function GenericNode({
selected: boolean, selected: boolean,
showNode: boolean, showNode: boolean,
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: VertexBuildTypeAPI | null, validationStatus: validationStatusType | null
) => { ) => {
const specificClassFromBuildStatus = getSpecificClassFromBuildStatus( const specificClassFromBuildStatus = getSpecificClassFromBuildStatus(
buildStatus, buildStatus,
validationStatus, validationStatus,
isDark, isDark
); );
const baseBorderClass = getBaseBorderClass(selected); const baseBorderClass = getBaseBorderClass(selected);
@ -128,7 +128,7 @@ export default function GenericNode({
baseBorderClass, baseBorderClass,
nodeSizeClass, nodeSizeClass,
"generic-node-div", "generic-node-div",
specificClassFromBuildStatus, specificClassFromBuildStatus
); );
return names; return names;
}; };
@ -170,7 +170,7 @@ export default function GenericNode({
showNode, showNode,
isEmoji, isEmoji,
nodeIconFragment, nodeIconFragment,
checkNodeIconFragment, checkNodeIconFragment
); );
function countHandles(): void { function countHandles(): void {
@ -247,7 +247,7 @@ export default function GenericNode({
selected, selected,
showNode, showNode,
buildStatus, buildStatus,
validationStatus, validationStatus
)} )}
> >
{data.node?.beta && showNode && ( {data.node?.beta && showNode && (
@ -378,7 +378,7 @@ export default function GenericNode({
} }
title={getFieldTitle( title={getFieldTitle(
data.node?.template!, data.node?.template!,
templateField, templateField
)} )}
info={data.node?.template[templateField].info} info={data.node?.template[templateField].info}
name={templateField} name={templateField}
@ -406,7 +406,7 @@ export default function GenericNode({
proxy={data.node?.template[templateField].proxy} proxy={data.node?.template[templateField].proxy}
showNode={showNode} showNode={showNode}
/> />
), )
)} )}
<ParameterComponent <ParameterComponent
key={scapedJSONStringfy({ key={scapedJSONStringfy({
@ -552,7 +552,7 @@ export default function GenericNode({
!data.node?.description) && !data.node?.description) &&
nameEditable nameEditable
? "font-light italic" ? "font-light italic"
: "", : ""
)} )}
onClick={(e) => { onClick={(e) => {
setInputDescription(true); setInputDescription(true);
@ -614,13 +614,13 @@ export default function GenericNode({
} }
title={getFieldTitle( title={getFieldTitle(
data.node?.template!, data.node?.template!,
templateField, templateField
)} )}
info={data.node?.template[templateField].info} info={data.node?.template[templateField].info}
name={templateField} name={templateField}
tooltipTitle={ tooltipTitle={
data.node?.template[templateField].input_types?.join( data.node?.template[templateField].input_types?.join(
"\n", "\n"
) ?? data.node?.template[templateField].type ) ?? data.node?.template[templateField].type
} }
required={data.node!.template[templateField].required} required={data.node!.template[templateField].required}
@ -647,7 +647,7 @@ export default function GenericNode({
<div <div
className={classNames( className={classNames(
Object.keys(data.node!.template).length < 1 ? "hidden" : "", Object.keys(data.node!.template).length < 1 ? "hidden" : "",
"flex-max-width justify-center", "flex-max-width justify-center"
)} )}
> >
{" "} {" "}

View file

@ -2,7 +2,7 @@ import { APITemplateType } from "../../types/api";
export default function getFieldTitle( export default function getFieldTitle(
template: APITemplateType, template: APITemplateType,
templateField: string, templateField: string
): string { ): string {
return template[templateField].display_name return template[templateField].display_name
? template[templateField].display_name! ? template[templateField].display_name!

View file

@ -0,0 +1,25 @@
export default function SvgStreamlit(props) {
return (
<svg
width="301"
height="165"
viewBox="0 0 301 165"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M150.731 101.547L98.1387 73.7471L6.84674 25.4969C6.7634 25.4136 6.59674 25.4136 6.51341 25.4136C3.18007 23.8303 -0.236608 27.1636 1.0134 30.497L47.5302 149.139L47.5385 149.164C47.5885 149.281 47.6302 149.397 47.6802 149.514C49.5885 153.939 53.7552 156.672 58.2886 157.747C58.6719 157.831 58.9461 157.906 59.4064 157.998C59.8645 158.1 60.5052 158.239 61.0552 158.281C61.1469 158.289 61.2302 158.289 61.3219 158.297H61.3886C61.4552 158.306 61.5219 158.306 61.5886 158.314H61.6802C61.7386 158.322 61.8052 158.322 61.8636 158.322H61.9719C62.0386 158.331 62.1052 158.331 62.1719 158.331V158.331C121.084 164.754 180.519 164.754 239.431 158.331V158.331C240.139 158.331 240.831 158.297 241.497 158.231C241.714 158.206 241.922 158.181 242.131 158.156C242.156 158.147 242.189 158.147 242.214 158.139C242.356 158.122 242.497 158.097 242.639 158.072C242.847 158.047 243.056 158.006 243.264 157.964C243.681 157.872 243.87 157.806 244.436 157.611C245.001 157.417 245.94 157.077 246.527 156.794C247.115 156.511 247.522 156.239 248.014 155.931C248.622 155.547 249.201 155.155 249.788 154.715C250.041 154.521 250.214 154.397 250.397 154.222L250.297 154.164L150.731 101.547Z"
fill="#FF4B4B"
/>
<path
d="M294.766 25.4981H294.683L203.357 73.7483L254.124 149.357L300.524 30.4981V30.3315C301.691 26.8314 298.108 23.6648 294.766 25.4981"
fill="#7D353B"
/>
<path
d="M155.598 2.55572C153.264 -0.852624 148.181 -0.852624 145.931 2.55572L98.1389 73.7477L150.731 101.548L250.398 154.222C251.024 153.609 251.526 153.012 252.056 152.381C252.806 151.456 253.506 150.465 254.123 149.356L203.356 73.7477L155.598 2.55572Z"
fill="#BD4043"
/>
</svg>
);
}

View file

@ -0,0 +1,8 @@
import React, { forwardRef } from "react";
import SvgStreamlit from "./SvgStreamlit";
export const Streamlit = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>(
(props, ref) => {
return <SvgStreamlit className="icon" ref={ref} {...props} />;
}
);

View file

@ -27,7 +27,7 @@ const useFolderSubmit = (setOpen, folderToEdit) => {
getFoldersApi(true); getFoldersApi(true);
setOpen(false); setOpen(false);
} }
}, }
); );
} else { } else {
addFolder(data).then( addFolder(data).then(
@ -42,7 +42,7 @@ const useFolderSubmit = (setOpen, folderToEdit) => {
setErrorData({ setErrorData({
title: `Error creating folder.`, title: `Error creating folder.`,
}); });
}, }
); );
} }
}; };

View file

@ -114,19 +114,19 @@ export default function ChatMessage({
<div <div
className={classNames( className={classNames(
"form-modal-chat-position", "form-modal-chat-position",
chat.isSend ? "" : " ", chat.isSend ? "" : " "
)} )}
> >
<div <div
className={classNames( className={classNames(
"mr-3 mt-1 flex w-24 flex-col items-center gap-1 overflow-hidden px-3 pb-3", "mr-3 mt-1 flex w-24 flex-col items-center gap-1 overflow-hidden px-3 pb-3"
)} )}
> >
<div className="flex flex-col items-center gap-1"> <div className="flex flex-col items-center gap-1">
<div <div
className={cn( className={cn(
"relative flex h-8 w-8 items-center justify-center overflow-hidden rounded-md p-5 text-2xl", "relative flex h-8 w-8 items-center justify-center overflow-hidden rounded-md p-5 text-2xl",
!chat.isSend ? "bg-chat-bot-icon" : "bg-chat-user-icon", !chat.isSend ? "bg-chat-bot-icon" : "bg-chat-user-icon"
)} )}
> >
<img <img
@ -210,12 +210,12 @@ dark:prose-invert"
children[0] = (children[0] as string).replace( children[0] = (children[0] as string).replace(
"`▍`", "`▍`",
"▍", "▍"
); );
} }
const match = /language-(\w+)/.exec( const match = /language-(\w+)/.exec(
className || "", className || ""
); );
return !inline ? ( return !inline ? (
@ -230,12 +230,12 @@ dark:prose-invert"
language: (match && match[1]) || "", language: (match && match[1]) || "",
code: String(children).replace( code: String(children).replace(
/\n$/, /\n$/,
"", ""
), ),
}, },
]} ]}
activeTab={"0"} activeTab={"0"}
setActiveTab={() => { }} setActiveTab={() => {}}
/> />
) : ( ) : (
<code className={className} {...props}> <code className={className} {...props}>
@ -248,7 +248,7 @@ dark:prose-invert"
{chatMessage} {chatMessage}
</Markdown> </Markdown>
), ),
[chat.message, chatMessage], [chat.message, chatMessage]
)} )}
</div> </div>
</div> </div>

View file

@ -1,11 +1,6 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import IconComponent from "../../../../components/genericIconComponent"; import IconComponent from "../../../../components/genericIconComponent";
import { import { Button } from "../../../../components/ui/button";
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from "../../../../components/ui/select";
import { import {
CHAT_FIRST_INITIAL_TEXT, CHAT_FIRST_INITIAL_TEXT,
CHAT_SECOND_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT,
@ -67,7 +62,7 @@ export default function ChatView({
.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)) .sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp))
// //
.filter( .filter(
(output) => output.data.messages && output.data.messages.length > 0, (output) => output.data.messages && output.data.messages.length > 0
) )
.map((output, index) => { .map((output, index) => {
try { try {
@ -136,7 +131,7 @@ export default function ChatView({
function updateChat( function updateChat(
chat: ChatMessageType, chat: ChatMessageType,
message: string, message: string,
stream_url?: string, stream_url?: string
) { ) {
// if (message === "") return; // if (message === "") return;
chat.message = message; chat.message = message;
@ -164,19 +159,21 @@ export default function ChatView({
<div className="eraser-column-arrangement"> <div className="eraser-column-arrangement">
<div className="eraser-size"> <div className="eraser-size">
<div className="eraser-position"> <div className="eraser-position">
<button <Button
className="flex gap-1" className="flex gap-1"
size="none"
variant="none"
onClick={() => handleSelectChange("builds")} onClick={() => handleSelectChange("builds")}
> >
<IconComponent <IconComponent
name="Eraser" name="Eraser"
className={classNames( className={classNames(
"h-5 w-5 transition-all duration-100", "h-5 w-5 transition-all duration-100",
lockChat ? "animate-pulse text-primary" : "text-primary", lockChat ? "animate-pulse text-primary" : "text-primary"
)} )}
aria-hidden="true" aria-hidden="true"
/> />
</button> </Button>
{/* <Select {/* <Select
onValueChange={handleSelectChange} onValueChange={handleSelectChange}
value="" value=""

View file

@ -34,25 +34,25 @@ export default function IOModal({
}: IOModalPropsType): JSX.Element { }: IOModalPropsType): JSX.Element {
const allNodes = useFlowStore((state) => state.nodes); const allNodes = useFlowStore((state) => state.nodes);
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( const chatInput = useFlowStore((state) => state.inputs).find(
(input) => input.type === "ChatInput", (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( const chatOutput = useFlowStore((state) => state.outputs).find(
(output) => output.type === "ChatOutput", (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)
); );
const haveChat = chatInput || 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
); );
function startView() { function startView() {
@ -161,7 +161,7 @@ export default function IOModal({
{selectedTab !== 0 && ( {selectedTab !== 0 && (
<div <div
className={cn( className={cn(
"mr-6 flex h-full w-2/6 flex-shrink-0 flex-col justify-start transition-all duration-300", "mr-6 flex h-full w-2/6 flex-shrink-0 flex-col justify-start transition-all duration-300"
)} )}
> >
<Tabs <Tabs
@ -197,11 +197,11 @@ export default function IOModal({
</div> </div>
{nodes {nodes
.filter((node) => .filter((node) =>
inputs.some((input) => input.id === node.id), inputs.some((input) => input.id === node.id)
) )
.map((node, index) => { .map((node, index) => {
const input = inputs.find( const input = inputs.find(
(input) => input.id === node.id, (input) => input.id === node.id
)!; )!;
return ( return (
<div <div
@ -265,11 +265,11 @@ export default function IOModal({
</div> </div>
{nodes {nodes
.filter((node) => .filter((node) =>
outputs.some((output) => output.id === node.id), outputs.some((output) => output.id === node.id)
) )
.map((node, index) => { .map((node, index) => {
const output = outputs.find( const output = outputs.find(
(output) => output.id === node.id, (output) => output.id === node.id
)!; )!;
return ( return (
<div <div
@ -336,7 +336,7 @@ export default function IOModal({
<div <div
className={cn( className={cn(
"flex h-full w-full flex-col items-start gap-4 pt-4", "flex h-full w-full flex-col items-start gap-4 pt-4",
!selectedViewField ? "hidden" : "", !selectedViewField ? "hidden" : ""
)} )}
> >
<div className="font-xl flex items-center justify-center gap-3 font-semibold"> <div className="font-xl flex items-center justify-center gap-3 font-semibold">
@ -355,7 +355,7 @@ export default function IOModal({
</div> </div>
<div className="h-full w-full"> <div className="h-full w-full">
{inputs.some( {inputs.some(
(input) => input.id === selectedViewField.id, (input) => input.id === selectedViewField.id
) ? ( ) ? (
<IOFieldView <IOFieldView
type={InputOutput.INPUT} type={InputOutput.INPUT}
@ -377,7 +377,7 @@ export default function IOModal({
<div <div
className={cn( className={cn(
"flex h-full w-full", "flex h-full w-full",
selectedViewField ? "hidden" : "", selectedViewField ? "hidden" : ""
)} )}
> >
{haveChat ? ( {haveChat ? (
@ -409,7 +409,7 @@ export default function IOModal({
"h-4 w-4", "h-4 w-4",
isBuilding isBuilding
? "animate-spin" ? "animate-spin"
: "fill-current text-medium-indigo", : "fill-current text-medium-indigo"
)} )}
/> />
), ),

View file

@ -6,7 +6,7 @@ export const checkCanBuildTweakObject = (element, templateField) => {
templateField.charAt(0) !== "_" && templateField.charAt(0) !== "_" &&
element.data.node.template[templateField].show && element.data.node.template[templateField].show &&
LANGFLOW_SUPPORTED_TYPES.has( LANGFLOW_SUPPORTED_TYPES.has(
element.data.node.template[templateField].type, element.data.node.template[templateField].type
) && ) &&
templateField !== "code" templateField !== "code"
); );

View file

@ -3,7 +3,7 @@ import { convertArrayToObj } from "../../../utils/reactflowUtils";
export const getChangesType = ( export const getChangesType = (
changes: string | string[] | boolean | number | Object[] | Object, changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType, template: TemplateVariableType
) => { ) => {
if (typeof changes === "string" && template.type === "float") { if (typeof changes === "string" && template.type === "float") {
changes = parseFloat(changes); changes = parseFloat(changes);

View file

@ -8,7 +8,7 @@ export function getCurlRunCode(
flowId: string, flowId: string,
isAuth: boolean, isAuth: boolean,
tweaksBuildedObject, tweaksBuildedObject,
endpointName?: string, endpointName?: string
): string { ): string {
const tweaksObject = tweaksBuildedObject[0]; const tweaksObject = tweaksBuildedObject[0];
// show the endpoint name in the curl command if it exists // show the endpoint name in the curl command if it exists

View file

@ -13,8 +13,8 @@ export const getNodesWithDefaultValue = (flow) => {
templateField.charAt(0) !== "_" && templateField.charAt(0) !== "_" &&
node.data.node.template[templateField].show && node.data.node.template[templateField].show &&
LANGFLOW_SUPPORTED_TYPES.has( LANGFLOW_SUPPORTED_TYPES.has(
node.data.node.template[templateField].type, node.data.node.template[templateField].type
), )
) )
.map((n, i) => { .map((n, i) => {
arrNodesWithValues.push(node["id"]); arrNodesWithValues.push(node["id"]);

View file

@ -6,7 +6,7 @@
*/ */
export default function getPythonCode( export default function getPythonCode(
flowName: string, flowName: string,
tweaksBuildedObject, tweaksBuildedObject
): string { ): string {
const tweaksObject = tweaksBuildedObject[0]; const tweaksObject = tweaksBuildedObject[0];

View file

@ -5,7 +5,7 @@ export const getValue = (
value: string, value: string,
node: NodeType, node: NodeType,
template: TemplateVariableType, template: TemplateVariableType,
tweak: Object[], tweak: Object[]
) => { ) => {
let returnValue = value ?? ""; let returnValue = value ?? "";

View file

@ -6,7 +6,7 @@
export default function getWidgetCode( export default function getWidgetCode(
flowId: string, flowId: string,
flowName: string, flowName: string,
isAuth: boolean, isAuth: boolean
): string { ): string {
return `<script src="https://cdn.jsdelivr.net/gh/langflow-ai/langflow-embedded-chat@1.0_alpha/dist/build/static/js/bundle.min.js"></script> return `<script src="https://cdn.jsdelivr.net/gh/langflow-ai/langflow-embedded-chat@1.0_alpha/dist/build/static/js/bundle.min.js"></script>

View file

@ -1,7 +1,7 @@
export function createTabsArray( export function createTabsArray(
codes, codes,
includeWebhookCurl = false, includeWebhookCurl = false,
includeTweaks = false, includeTweaks = false
) { ) {
const tabs = [ const tabs = [
{ {

View file

@ -35,7 +35,7 @@ const ApiModal = forwardRef(
flow: FlowType; flow: FlowType;
children: ReactNode; children: ReactNode;
}, },
ref, ref
) => { ) => {
const tweak = useTweaksStore((state) => state.tweak); const tweak = useTweaksStore((state) => state.tweak);
const addTweaks = useTweaksStore((state) => state.setTweak); const addTweaks = useTweaksStore((state) => state.setTweak);
@ -50,22 +50,21 @@ const ApiModal = forwardRef(
flow?.id, flow?.id,
autoLogin, autoLogin,
tweak, tweak,
flow?.endpoint_name, flow?.endpoint_name
); );
const curl_run_code = getCurlRunCode( const curl_run_code = getCurlRunCode(
flow?.id, flow?.id,
autoLogin, autoLogin,
tweak, tweak,
flow?.endpoint_name, flow?.endpoint_name
); );
const curl_webhook_code = getCurlWebhookCode( const curl_webhook_code = getCurlWebhookCode(
flow?.id, flow?.id,
autoLogin, autoLogin,
flow?.endpoint_name, flow?.endpoint_name
); );
const pythonCode = getPythonCode(flow?.name, tweak); const pythonCode = getPythonCode(flow?.name, tweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin); const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
const includeWebhook = flow.webhook; const includeWebhook = flow.webhook;
const tweaksCode = buildTweaks(flow); const tweaksCode = buildTweaks(flow);
const codesArray = [ const codesArray = [
@ -77,7 +76,7 @@ const ApiModal = forwardRef(
pythonCode, pythonCode,
]; ];
const [tabs, setTabs] = useState( const [tabs, setTabs] = useState(
createTabsArray(codesArray, includeWebhook), createTabsArray(codesArray, includeWebhook)
); );
const canShowTweaks = const canShowTweaks =
@ -126,7 +125,7 @@ const ApiModal = forwardRef(
buildTweakObject( buildTweakObject(
nodeId, nodeId,
element.data.node.template[templateField].value, element.data.node.template[templateField].value,
element.data.node.template[templateField], element.data.node.template[templateField]
); );
} }
}); });
@ -143,7 +142,7 @@ const ApiModal = forwardRef(
async function buildTweakObject( async function buildTweakObject(
tw: string, tw: string,
changes: string | string[] | boolean | number | Object[] | Object, changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType, template: TemplateVariableType
) { ) {
changes = getChangesType(changes, template); changes = getChangesType(changes, template);
@ -185,7 +184,7 @@ const ApiModal = forwardRef(
flow?.id, flow?.id,
autoLogin, autoLogin,
cloneTweak, cloneTweak,
flow?.endpoint_name, flow?.endpoint_name
); );
const pythonCode = getPythonCode(flow?.name, cloneTweak); const pythonCode = getPythonCode(flow?.name, cloneTweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin); const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
@ -229,7 +228,7 @@ const ApiModal = forwardRef(
</BaseModal.Content> </BaseModal.Content>
</BaseModal> </BaseModal>
); );
}, }
); );
export default ApiModal; export default ApiModal;

View file

@ -4,7 +4,7 @@ export const switchCaseModalSize = (size: string) => {
switch (size) { switch (size) {
case "x-small": case "x-small":
minWidth = "min-w-[20vw]"; minWidth = "min-w-[20vw]";
height = "h-full"; height = "";
break; break;
case "smaller": case "smaller":
minWidth = "min-w-[40vw]"; minWidth = "min-w-[40vw]";
@ -12,7 +12,7 @@ export const switchCaseModalSize = (size: string) => {
break; break;
case "smaller-h-full": case "smaller-h-full":
minWidth = "min-w-[40vw]"; minWidth = "min-w-[40vw]";
height = "h-full"; height = "";
break; break;
case "small": case "small":
minWidth = "min-w-[40vw]"; minWidth = "min-w-[40vw]";
@ -20,16 +20,19 @@ export const switchCaseModalSize = (size: string) => {
break; break;
case "small-h-full": case "small-h-full":
minWidth = "min-w-[40vw]"; minWidth = "min-w-[40vw]";
height = "h-full"; height = "";
break; break;
case "medium": case "medium":
minWidth = "min-w-[60vw]"; minWidth = "min-w-[60vw]";
height = "h-[60vh]"; height = "h-[60vh]";
break; break;
case "medium-tall":
minWidth = "min-w-[60vw]";
height = "h-[90vh]";
break;
case "medium-h-full": case "medium-h-full":
minWidth = "min-w-[60vw]"; minWidth = "min-w-[60vw]";
height = "h-full"; height = "";
break; break;
case "large": case "large":
minWidth = "min-w-[85vw]"; minWidth = "min-w-[85vw]";
@ -56,11 +59,11 @@ export const switchCaseModalSize = (size: string) => {
case "large-h-full": case "large-h-full":
minWidth = "min-w-[80vw]"; minWidth = "min-w-[80vw]";
height = "h-full"; height = "";
break; break;
default: default:
minWidth = "min-w-[80vw]"; minWidth = "min-w-[80vw]";
height = "h-[80vh]"; height = "h-[90vh]";
break; break;
} }
return { minWidth, height }; return { minWidth, height };

View file

@ -20,6 +20,7 @@ import { Button } from "../../components/ui/button";
import { modalHeaderType } from "../../types/components"; import { modalHeaderType } from "../../types/components";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import { switchCaseModalSize } from "./helpers/switch-case-size"; import { switchCaseModalSize } from "./helpers/switch-case-size";
import * as Form from "@radix-ui/react-form";
type ContentProps = { children: ReactNode }; type ContentProps = { children: ReactNode };
type HeaderProps = { children: ReactNode; description: string }; type HeaderProps = { children: ReactNode; description: string };
@ -52,10 +53,10 @@ const Trigger: React.FC<TriggerProps> = ({
); );
}; };
const Header: React.FC<{ children: ReactNode; description: string | null }> = ({ const Header: React.FC<{
children, children: ReactNode;
description, description: string | JSX.Element | null;
}: modalHeaderType): JSX.Element => { }> = ({ children, description }: modalHeaderType): JSX.Element => {
return ( return (
<DialogHeader> <DialogHeader>
<DialogTitle className="flex items-center">{children}</DialogTitle> <DialogTitle className="flex items-center">{children}</DialogTitle>
@ -102,7 +103,7 @@ interface BaseModalProps {
React.ReactElement<ContentProps>, React.ReactElement<ContentProps>,
React.ReactElement<HeaderProps>, React.ReactElement<HeaderProps>,
React.ReactElement<TriggerProps>?, React.ReactElement<TriggerProps>?,
React.ReactElement<FooterProps>?, React.ReactElement<FooterProps>?
]; ];
open?: boolean; open?: boolean;
setOpen?: (open: boolean) => void; setOpen?: (open: boolean) => void;
@ -111,6 +112,7 @@ interface BaseModalProps {
| "smaller" | "smaller"
| "small" | "small"
| "medium" | "medium"
| "medium-tall"
| "large" | "large"
| "three-cards" | "three-cards"
| "large-thin" | "large-thin"
@ -137,16 +139,16 @@ function BaseModal({
onSubmit, onSubmit,
}: BaseModalProps) { }: BaseModalProps) {
const headerChild = React.Children.toArray(children).find( const headerChild = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Header, (child) => (child as React.ReactElement).type === Header
); );
const triggerChild = React.Children.toArray(children).find( const triggerChild = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Trigger, (child) => (child as React.ReactElement).type === Trigger
); );
const ContentChild = React.Children.toArray(children).find( const ContentChild = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Content, (child) => (child as React.ReactElement).type === Content
); );
const ContentFooter = React.Children.toArray(children).find( const ContentFooter = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Footer, (child) => (child as React.ReactElement).type === Footer
); );
let { minWidth, height } = switchCaseModalSize(size); let { minWidth, height } = switchCaseModalSize(size);
@ -180,31 +182,33 @@ function BaseModal({
) : ( ) : (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
{triggerChild} {triggerChild}
<DialogContent className={cn(minWidth, "duration-300")}> <DialogContent
className={cn(minWidth, height, "flex flex-col duration-300")}
>
<div className="truncate-doubleline word-break-break-word"> <div className="truncate-doubleline word-break-break-word">
{headerChild} {headerChild}
</div> </div>
{onSubmit ? ( {onSubmit ? (
<form <Form.Root
onSubmit={(event) => { onSubmit={(event) => {
event.preventDefault(); event.preventDefault();
onSubmit(); onSubmit();
}} }}
className="flex flex-col gap-6" className="flex flex-1 flex-col gap-6"
> >
<div <div
className={`flex flex-col ${height} w-full transition-all duration-300`} className={`flex w-full flex-1 flex-col transition-all duration-300`}
> >
{ContentChild} {ContentChild}
</div> </div>
{ContentFooter && ( {ContentFooter && (
<div className="flex flex-row-reverse">{ContentFooter}</div> <div className="flex flex-row-reverse">{ContentFooter}</div>
)} )}
</form> </Form.Root>
) : ( ) : (
<> <>
<div <div
className={`flex flex-col ${height} w-full transition-all duration-300`} className={`flex w-full flex-1 flex-col transition-all duration-300`}
> >
{ContentChild} {ContentChild}
</div> </div>

View file

@ -0,0 +1,91 @@
import { ColDef, ValueGetterParams } from "ag-grid-community";
import { useMemo } from "react";
import TableAutoCellRender from "../../../components/tableComponent/components/tableAutoCellRender";
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
import TableToggleCellRender from "../../../components/tableComponent/components/tableToggleCellRender";
import TableTooltipRender from "../../../components/tableComponent/components/tableTooltipRender";
const useColumnDefs = (
myData: any,
handleOnNewValue: (newValue: any, name: string) => void,
changeAdvanced: (n: string) => void,
open: boolean,
) => {
const columnDefs: ColDef[] = useMemo(
() => [
{
headerName: "Name",
field: "display_name",
valueGetter: (params) => {
const templateParam = params.data;
return (
(templateParam.display_name
? templateParam.display_name
: templateParam.name) ?? params.data.key
);
},
tooltipField: "display_name",
tooltipComponent: TableTooltipRender,
wrapText: true,
autoHeight: true,
flex: 1,
resizable: false,
cellClass: "no-border",
},
{
headerName: "Description",
field: "info",
tooltipField: "info",
tooltipComponent: TableTooltipRender,
wrapText: true,
autoHeight: true,
flex: 2,
resizable: false,
cellClass: "no-border",
},
{
headerName: "Value",
field: "value",
cellRenderer: TableNodeCellRender,
valueGetter: (params: ValueGetterParams) => {
return {
value: params.data.value,
nodeClass: myData.node,
handleOnNewValue: handleOnNewValue,
handleOnChangeDb: (value, key) => {
myData.node!.template[key].load_from_db = value;
},
};
},
minWidth: 330,
autoHeight: true,
flex: 1,
resizable: false,
cellClass: "no-border",
},
{
headerName: "Show",
field: "advanced",
cellRenderer: TableToggleCellRender,
valueGetter: (params: ValueGetterParams) => {
return {
name: params.data.name,
enabled: !params.data.advanced,
setEnabled: () => {
changeAdvanced(params.data.key);
},
};
},
editable: false,
maxWidth: 80,
resizable: false,
cellClass: "no-border",
},
],
[open, myData],
);
return columnDefs;
};
export default useColumnDefs;

View file

@ -0,0 +1,37 @@
import { useMemo } from "react";
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
import { TemplateVariableType } from "../../../types/api";
const useRowData = (myData, open) => {
const rowData = useMemo(() => {
return Object.keys(myData.node!.template)
.filter((key: string) => {
const templateParam = myData.node!.template[
key
] as TemplateVariableType;
return (
key.charAt(0) !== "_" &&
templateParam.show &&
LANGFLOW_SUPPORTED_TYPES.has(templateParam.type) &&
!(
(key === "code" && templateParam.type === "code") ||
(key.includes("code") && templateParam.proxy)
)
);
})
.map((key: string) => {
const templateParam = myData.node!.template[
key
] as TemplateVariableType;
return {
...templateParam,
key: key,
id: key,
};
});
}, [open, myData]);
return rowData;
};
export default useRowData;

View file

@ -1,43 +1,13 @@
import { cloneDeep } from "lodash"; import { ColDef, GridApi } from "ag-grid-community";
import { forwardRef, useEffect, useState } from "react"; import { forwardRef, useEffect, useRef, useState } from "react";
import CodeAreaComponent from "../../components/codeAreaComponent";
import DictComponent from "../../components/dictComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
import IconComponent from "../../components/genericIconComponent"; import IconComponent from "../../components/genericIconComponent";
import InputFileComponent from "../../components/inputFileComponent"; import TableComponent from "../../components/tableComponent";
import InputGlobalComponent from "../../components/inputGlobalComponent";
import InputListComponent from "../../components/inputListComponent";
import IntComponent from "../../components/intComponent";
import KeypairListComponent from "../../components/keypairListComponent";
import PromptAreaComponent from "../../components/promptComponent";
import ShadTooltip from "../../components/shadTooltipComponent";
import TextAreaComponent from "../../components/textAreaComponent";
import ToggleShadComponent from "../../components/toggleShadComponent";
import { Badge } from "../../components/ui/badge"; import { Badge } from "../../components/ui/badge";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import {
LANGFLOW_SUPPORTED_TYPES,
limitScrollFieldsModal,
} from "../../constants/constants";
import { Case } from "../../shared/components/caseComponent";
import useFlowStore from "../../stores/flowStore"; import useFlowStore from "../../stores/flowStore";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import {
convertObjToArray,
convertValuesToNumbers,
hasDuplicateKeys,
scapedJSONStringfy,
} from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
import useColumnDefs from "./hooks/use-column-defs";
import useRowData from "./hooks/use-row-data";
const EditNodeModal = forwardRef( const EditNodeModal = forwardRef(
( (
@ -52,61 +22,51 @@ const EditNodeModal = forwardRef(
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void;
data: NodeDataType; data: NodeDataType;
}, },
ref, ref
) => { ) => {
const nodes = useFlowStore((state) => state.nodes); const myData = useRef(data);
const dataFromStore = nodes.find((node) => node.id === node.id)?.data;
const [myData, setMyData] = useState(dataFromStore ?? data);
const edges = useFlowStore((state) => state.edges);
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
function changeAdvanced(n) { function changeAdvanced(n) {
setMyData((old) => { myData.current.node!.template[n].advanced =
let newData = cloneDeep(old); !myData.current.node!.template[n]?.advanced;
newData.node!.template[n].advanced =
!newData.node!.template[n].advanced;
return newData;
});
} }
const handleOnNewValue = (newValue: any, name) => { const handleOnNewValue = (newValue: any, name) => {
setMyData((old) => { myData.current.node!.template[name].value = newValue;
let newData = cloneDeep(old);
newData.node!.template[name].value = newValue;
return newData;
});
}; };
const rowData = useRowData(data, open);
const columnDefs: ColDef[] = useColumnDefs(
data,
handleOnNewValue,
changeAdvanced,
open
);
const [gridApi, setGridApi] = useState<GridApi | null>(null);
useEffect(() => { useEffect(() => {
if (open) { if (gridApi && open) {
setMyData(data); // reset data to what it is on node when opening modal myData.current = data;
gridApi.refreshCells();
} }
}, [open]); }, [gridApi, open]);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
const type = (templateParam) => {
return myData.node?.template[templateParam].type;
};
return ( return (
<BaseModal <BaseModal
key={data.id} key={data.id}
size="large-h-full" size="medium-tall"
open={open} open={open}
setOpen={setOpen} setOpen={setOpen}
onChangeOpenModal={(open) => {
setMyData(data);
}}
onSubmit={() => { onSubmit={() => {
setNode(data.id, (old) => ({ setNode(data.id, (old) => ({
...old, ...old,
data: { data: {
...old.data, ...old.data,
node: myData.node, node: myData.current.node,
}, },
})); }));
setOpen(false); setOpen(false);
@ -115,11 +75,12 @@ const EditNodeModal = forwardRef(
<BaseModal.Trigger> <BaseModal.Trigger>
<></> <></>
</BaseModal.Trigger> </BaseModal.Trigger>
<BaseModal.Header description={myData.node?.description!}> <BaseModal.Header description={data.node?.description!}>
<span className="pr-2">{myData.type}</span> <span className="pr-2">{data.type}</span>
<Badge variant="secondary">ID: {myData.id}</Badge> <Badge variant="secondary">ID: {data.id}</Badge>
</BaseModal.Header> </BaseModal.Header>
<BaseModal.Content> <BaseModal.Content>
<div className="flex h-full flex-col">
<div className="flex pb-2"> <div className="flex pb-2">
<IconComponent <IconComponent
name="Variable" name="Variable"
@ -128,513 +89,16 @@ const EditNodeModal = forwardRef(
<span className="edit-node-modal-span">Parameters</span> <span className="edit-node-modal-span">Parameters</span>
</div> </div>
<div className="edit-node-modal-arrangement"> <div className="h-full">
<div
className={classNames(
"edit-node-modal-box",
nodeLength > limitScrollFieldsModal
? "overflow-scroll overflow-x-hidden custom-scroll"
: "",
)}
>
{nodeLength > 0 && ( {nodeLength > 0 && (
<div className="edit-node-modal-table"> <TableComponent
<Table className="table-fixed bg-muted outline-1"> onGridReady={(params) => {
<TableHeader className="edit-node-modal-table-header"> setGridApi(params.api);
<TableRow className="">
<TableHead className="h-7 text-center">PARAM</TableHead>
<TableHead className="h-7 text-center">DESC</TableHead>
<TableHead className="h-7 p-0 text-center">
VALUE
</TableHead>
<TableHead className="h-7 text-center">SHOW</TableHead>
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(myData.node!.template)
.filter(
(templateParam) =>
templateParam.charAt(0) !== "_" &&
myData.node?.template[templateParam].show &&
LANGFLOW_SUPPORTED_TYPES.has(
myData.node!.template[templateParam].type,
),
)
.map((templateParam, index) => {
let id = {
inputTypes:
myData.node!.template[templateParam].input_types,
type: myData.node!.template[templateParam].type,
id: myData.id,
fieldName: templateParam,
};
let disabled =
edges.some(
(edge) =>
edge.targetHandle ===
scapedJSONStringfy(
myData.node!.template[templateParam].proxy
? {
...id,
proxy:
myData.node?.template[templateParam]
.proxy,
}
: id,
),
) ?? false;
return (
<TableRow
key={index}
className={
"h-10 " +
((templateParam === "code" &&
type(templateParam) === "code") ||
(templateParam.includes("code") &&
myData.node?.template[templateParam].proxy)
? " hidden "
: "")
}
>
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
<ShadTooltip
styleClasses="z-50"
content={
myData.node?.template[templateParam].proxy
? myData.node?.template[templateParam]
.proxy?.id
: myData.node?.template[templateParam]
.display_name
? myData.node!.template[templateParam]
.display_name
: myData.node?.template[templateParam]
.name
}
>
<span>
{myData.node?.template[templateParam]
.display_name
? myData.node!.template[templateParam]
.display_name
: myData.node?.template[templateParam]
.name}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
<ShadTooltip
styleClasses="z-50"
content={
data.node?.template[templateParam]?.info ??
null
}
>
<span>
{data.node?.template[templateParam]?.info ??
""}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
<Case
condition={
type(templateParam) === "str" &&
!myData.node!.template[templateParam]
.options
}
>
<div className="mx-auto">
{myData.node!.template[templateParam]
?.list ? (
<InputListComponent
componentName={templateParam}
editNode={true}
disabled={disabled}
value={
!myData.node!.template[templateParam]
.value ||
myData.node!.template[templateParam]
.value === ""
? [""]
: myData.node!.template[
templateParam
].value
}
onChange={(value: string[]) => {
handleOnNewValue(
value,
templateParam,
);
}} }}
tooltipShowDelay={0.5}
columnDefs={columnDefs}
rowData={rowData}
/> />
) : myData.node!.template[templateParam]
.multiline ? (
<TextAreaComponent
id={
"textarea-edit-" +
myData.node!.template[templateParam]
.name
}
data-testid={
"textarea-edit-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(
value: string | string[],
) => {
handleOnNewValue(
value,
templateParam,
);
}}
/>
) : (
<InputGlobalComponent
disabled={disabled}
editNode={true}
onChange={(value) =>
handleOnNewValue(value, templateParam)
}
setDb={(value) => {
setMyData((oldData) => {
let newData = cloneDeep(oldData);
newData.node!.template[
templateParam
].load_from_db = value;
return newData;
});
}}
name={templateParam}
data={myData}
/>
)}
</div>
</Case>
<Case
condition={
type(templateParam) === "NestedDict"
}
>
<div className=" w-full">
<DictComponent
disabled={disabled}
editNode={true}
value={
myData.node!.template[
templateParam
]?.value?.toString() === "{}"
? {}
: myData.node!.template[templateParam]
.value
}
onChange={(newValue) => {
myData.node!.template[
templateParam
].value = newValue;
handleOnNewValue(
newValue,
templateParam,
);
}}
id="editnode-div-dict-input"
/>
</div>
</Case>
<Case
condition={type(templateParam) === "dict"}
>
<div
className={classNames(
"max-h-48 w-full overflow-auto custom-scroll",
myData.node!.template[templateParam].value
?.length > 1
? "my-3"
: "",
)}
>
<KeypairListComponent
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value?.length === 0 ||
!myData.node!.template[templateParam]
.value
? [{ "": "" }]
: convertObjToArray(
myData.node!.template[
templateParam
].value,
type(templateParam)!,
)
}
duplicateKey={errorDuplicateKey}
onChange={(newValue) => {
const valueToNumbers =
convertValuesToNumbers(newValue);
myData.node!.template[
templateParam
].value = valueToNumbers;
setErrorDuplicateKey(
hasDuplicateKeys(valueToNumbers),
);
handleOnNewValue(
valueToNumbers,
templateParam,
);
}}
isList={
data.node?.template[templateParam]
?.list ?? false
}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "bool"}
>
<div className="ml-auto">
{" "}
<ToggleShadComponent
id={
"toggle-edit-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
enabled={
myData.node!.template[templateParam]
.value
}
setEnabled={(isEnabled) => {
handleOnNewValue(
isEnabled,
templateParam,
);
}}
size="small"
editNode={true}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "float"}
>
<div className="mx-auto">
<FloatComponent
disabled={disabled}
editNode={true}
rangeSpec={
myData.node!.template[templateParam]
.rangeSpec
}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
</Case>
<Case
condition={
type(templateParam) === "str" &&
myData.node!.template[templateParam].options
}
>
<div className="mx-auto">
<Dropdown
editNode={true}
options={
myData.node!.template[templateParam]
.options
}
onSelect={(value) =>
handleOnNewValue(value, templateParam)
}
value={
myData.node!.template[templateParam]
.value ?? "Choose an option"
}
id={
"dropdown-edit-" +
myData.node!.template[templateParam]
.name
}
></Dropdown>
</div>
</Case>
<Case condition={type(templateParam) === "int"}>
<div className="mx-auto">
<IntComponent
rangeSpec={
data.node?.template[templateParam]
?.rangeSpec
}
id={
"edit-int-input-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "file"}
>
<div className="mx-auto">
<InputFileComponent
editNode={true}
disabled={disabled}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
fileTypes={
myData.node!.template[templateParam]
.fileTypes
}
onFileChange={(filePath: string) => {
data.node!.template[
templateParam
].file_path = filePath;
}}
></InputFileComponent>
</div>
</Case>
<Case
condition={type(templateParam) === "prompt"}
>
<div className="mx-auto">
<PromptAreaComponent
readonly={
myData.node?.flow ? true : false
}
field_name={templateParam}
editNode={true}
disabled={disabled}
nodeClass={myData.node}
setNodeClass={(nodeClass) => {
myData.node = nodeClass;
}}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
id={
"prompt-area-edit-" +
myData.node!.template[templateParam]
.name
}
data-testid={
"modal-prompt-input-" +
myData.node!.template[templateParam]
.name
}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "code"}
>
<div className="mx-auto">
<CodeAreaComponent
readonly={
myData.node?.flow &&
myData.node!.template[templateParam]
.dynamic
? true
: false
}
dynamic={
data.node!.template[templateParam]
?.dynamic ?? false
}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
}}
nodeClass={data.node}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
id={
"code-area-edit" +
myData.node!.template[templateParam]
.name
}
/>
</div>
</Case>
<Case condition={type(templateParam) === "Any"}>
<>-</>
</Case>
</TableCell>
<TableCell className="p-0 text-right">
<div className="items-center text-center">
<ToggleShadComponent
id={
"show" +
myData.node?.template[templateParam].name
}
enabled={
!myData.node?.template[templateParam]
.advanced
}
setEnabled={(e) => {
changeAdvanced(templateParam);
}}
disabled={disabled}
size="small"
editNode={true}
/>
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
)} )}
</div> </div>
</div> </div>
@ -643,7 +107,7 @@ const EditNodeModal = forwardRef(
<BaseModal.Footer submit={{ label: "Save Changes" }} /> <BaseModal.Footer submit={{ label: "Save Changes" }} />
</BaseModal> </BaseModal>
); );
}, }
); );
export default EditNodeModal; export default EditNodeModal;

View file

@ -45,7 +45,7 @@ const ExportModal = forwardRef(
is_component: false, is_component: false,
}, },
name!, name!,
description, description
); );
setNoticeData({ setNoticeData({
title: API_WARNING_NOTICE_ALERT, title: API_WARNING_NOTICE_ALERT,
@ -61,7 +61,7 @@ const ExportModal = forwardRef(
is_component: false, is_component: false,
}), }),
name!, name!,
description, description
); );
setOpen(false); setOpen(false);
}} }}
@ -102,6 +102,6 @@ const ExportModal = forwardRef(
<BaseModal.Footer submit={{ label: "Download Flow" }} /> <BaseModal.Footer submit={{ label: "Download Flow" }} />
</BaseModal> </BaseModal>
); );
}, }
); );
export default ExportModal; export default ExportModal;

View file

@ -1,5 +1,4 @@
import { ColDef, ColGroupDef } from "ag-grid-community"; import { ColDef, ColGroupDef } from "ag-grid-community";
import { AxiosError } from "axios";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent"; import IconComponent from "../../components/genericIconComponent";
import TableComponent from "../../components/tableComponent"; import TableComponent from "../../components/tableComponent";
@ -9,7 +8,7 @@ import useAlertStore from "../../stores/alertStore";
import useFlowStore from "../../stores/flowStore"; import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { FlowSettingsPropsType } from "../../types/components"; import { FlowSettingsPropsType } from "../../types/components";
import { FlowType, NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
export default function FlowLogsModal({ export default function FlowLogsModal({
@ -38,7 +37,7 @@ export default function FlowLogsModal({
const { columns, rows } = data; const { columns, rows } = data;
setColumns(columns.map((col) => ({ ...col, editable: true }))); setColumns(columns.map((col) => ({ ...col, editable: true })));
setRows(rows); setRows(rows);
}, }
); );
} }
@ -48,7 +47,7 @@ export default function FlowLogsModal({
.some((template) => template["stream"] && template["stream"].value); .some((template) => template["stream"] && template["stream"].value);
console.log( console.log(
haStream, haStream,
nodes.map((nodes) => (nodes.data as NodeDataType).node!.template), nodes.map((nodes) => (nodes.data as NodeDataType).node!.template)
); );
if (haStream) { if (haStream) {
setNoticeData({ setNoticeData({

View file

@ -1,5 +1,4 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import InputComponent from "../../../components/inputComponent";
import { import {
FormControl, FormControl,
FormField, FormField,

View file

@ -33,7 +33,7 @@ const useFolderSubmit = (setOpen, folderToEdit) => {
getFoldersApi(true); getFoldersApi(true);
setOpen(false); setOpen(false);
} }
}, }
); );
} else { } else {
addFolder(data).then( addFolder(data).then(
@ -49,7 +49,7 @@ const useFolderSubmit = (setOpen, folderToEdit) => {
setErrorData({ setErrorData({
title: `Error creating folder.`, title: `Error creating folder.`,
}); });
}, }
); );
} }
}; };

View file

@ -32,7 +32,7 @@ export default function NewFlowModal({
key={0} key={0}
flow={ flow={
examples.find( examples.find(
(e) => e.name == "Basic Prompting (Hello, World)", (e) => e.name == "Basic Prompting (Hello, World)"
)! )!
} }
/> />

View file

@ -11,15 +11,10 @@ import { nodeIconsLucide } from "../../utils/styleUtils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
export default function SecretKeyModal({ export default function SecretKeyModal({
title,
cancelText,
confirmationText,
children, children,
icon,
data, data,
onCloseModal, onCloseModal,
}: ApiKeyType) { }: ApiKeyType) {
const Icon: any = nodeIconsLucide[icon];
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [apiKeyName, setApiKeyName] = useState(data?.apikeyname ?? ""); const [apiKeyName, setApiKeyName] = useState(data?.apikeyname ?? "");
const [apiKeyValue, setApiKeyValue] = useState(""); const [apiKeyValue, setApiKeyValue] = useState("");
@ -66,38 +61,60 @@ export default function SecretKeyModal({
.catch((err) => {}); .catch((err) => {});
} }
function handleSubmitForm() {
if (!renderKey) {
setRenderKey(true);
handleAddNewKey();
} else {
setOpen(false);
}
}
return ( return (
<BaseModal size="small-h-full" open={open} setOpen={setOpen}> <BaseModal
onSubmit={handleSubmitForm}
size="small-h-full"
open={open}
setOpen={setOpen}
>
<BaseModal.Trigger>{children}</BaseModal.Trigger> <BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header description={""}> <BaseModal.Header
<span className="pr-2">{title}</span> description={
<Icon renderKey ? (
name="icon"
className="h-6 w-6 pl-1 text-foreground"
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
{renderKey === true && (
<> <>
<span className="text-xs"> {" "}
Please save this secret key somewhere safe and accessible. For Please save this secret key somewhere safe and accessible. For
security reasons,{" "} security reasons,{" "}
<strong>you won't be able to view it again</strong> through your <strong>you won't be able to view it again</strong> through your
account. If you lose this secret key, you'll need to generate a account. If you lose this secret key, you'll need to generate a
new one. new one.
</span> </>
<div className="flex pt-3"> ) : (
<>Create a secret API Key to use Langflow API.</>
)
}
>
<span className="pr-2">Create API Key</span>
<IconComponent
name="Key"
className="h-6 w-6 pl-1 text-foreground"
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
{renderKey ? (
<>
<div className="flex items-center gap-3">
<div className="w-full"> <div className="w-full">
<Input ref={inputRef} readOnly={true} value={apiKeyValue} /> <Input ref={inputRef} readOnly={true} value={apiKeyValue} />
</div> </div>
<div>
<Button <Button
className="ml-3"
onClick={() => { onClick={() => {
handleCopyClick(); handleCopyClick();
}} }}
variant="none"
size="none"
> >
{textCopied ? ( {textCopied ? (
<IconComponent name="Copy" className="h-4 w-4" /> <IconComponent name="Copy" className="h-4 w-4" />
@ -106,78 +123,29 @@ export default function SecretKeyModal({
)} )}
</Button> </Button>
</div> </div>
</div>
</> </>
)} ) : (
<Form.Field name="apikey">
<Form.Root <div className="flex items-center justify-between gap-2">
onSubmit={(event) => {
setRenderKey(true);
handleAddNewKey();
event.preventDefault();
}}
>
{renderKey === false && (
<div className="grid gap-5">
<Form.Field name="username">
<div
style={{
display: "flex",
alignItems: "baseline",
justifyContent: "space-between",
}}
>
<Form.Label className="data-[invalid]:label-invalid">
Name (optional){" "}
</Form.Label>
</div>
<Form.Control asChild> <Form.Control asChild>
<input <Input
//fake api key
id="primary-input"
value={apiKeyName}
ref={inputRef}
onChange={({ target: { value } }) => { onChange={({ target: { value } }) => {
setApiKeyName(value); setApiKeyName(value);
}} }}
value={apiKeyName} placeholder="Insert a name for your API Key"
className="primary-input"
placeholder="My key name"
/> />
</Form.Control> </Form.Control>
</div>
</Form.Field> </Form.Field>
</div>
)} )}
{renderKey === false && (
<div className="float-right">
<Button
type="button"
className="mr-3"
variant="outline"
onClick={() => {
setOpen(false);
}}
>
{cancelText}
</Button>
<Form.Submit asChild>
<Button className="mt-8">{confirmationText}</Button>
</Form.Submit>
</div>
)}
{renderKey === true && (
<div className="float-right">
<Button
onClick={() => {
setOpen(false);
setRenderKey(false);
}}
className="mt-8"
>
Done
</Button>
</div>
)}
</Form.Root>
</BaseModal.Content> </BaseModal.Content>
<BaseModal.Footer
submit={{ label: renderKey ? "Done" : "Create Secret Key" }}
/>
</BaseModal> </BaseModal>
); );
} }

View file

@ -128,14 +128,14 @@ export default function ShareModal({
title: "Error sharing " + is_component ? "component" : "flow", title: "Error sharing " + is_component ? "component" : "flow",
list: [err["response"]["data"]["detail"]], list: [err["response"]["data"]["detail"]],
}); });
}, }
); );
else else
updateFlowStore( updateFlowStore(
flow!, flow!,
getTagsIds(selectedTags, tags), getTagsIds(selectedTags, tags),
sharePublic, sharePublic,
unavaliableNames.find((e) => e.name === name)!.id, unavaliableNames.find((e) => e.name === name)!.id
).then(successShare, (err) => { ).then(successShare, (err) => {
setErrorData({ setErrorData({
title: "Error sharing " + is_component ? "component" : "flow", title: "Error sharing " + is_component ? "component" : "flow",
@ -203,7 +203,7 @@ export default function ShareModal({
setOpen={setOpen ?? internalSetOpen} setOpen={setOpen ?? internalSetOpen}
onSubmit={() => { onSubmit={() => {
const isNameAvailable = !unavaliableNames.some( const isNameAvailable = !unavaliableNames.some(
(element) => element.name === name, (element) => element.name === name
); );
if (isNameAvailable) { if (isNameAvailable) {

View file

@ -1,6 +1,6 @@
export default function getTagsIds( export default function getTagsIds(
tags: string[], tags: string[],
tagListId: { name: string; id: string }[], tagListId: { name: string; id: string }[]
) { ) {
return tags return tags
.map((tag) => tagListId.find((tagObj) => tagObj.name === tag))! .map((tag) => tagListId.find((tagObj) => tagObj.name === tag))!

View file

@ -1,291 +0,0 @@
import { useContext, useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent";
import ShadTooltip from "../../components/shadTooltipComponent";
import { Button } from "../../components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import { AuthContext } from "../../contexts/authContext";
import { deleteApiKey, getApiKey } from "../../controllers/API";
import ConfirmationModal from "../../modals/confirmationModal";
import SecretKeyModal from "../../modals/secretKeyModal";
import moment from "moment";
import Header from "../../components/headerComponent";
import {
DEL_KEY_ERROR_ALERT,
DEL_KEY_SUCCESS_ALERT,
} from "../../constants/alerts_constants";
import {
API_PAGE_PARAGRAPH_1,
API_PAGE_PARAGRAPH_2,
API_PAGE_USER_KEYS,
LAST_USED_SPAN_1,
LAST_USED_SPAN_2,
} from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import { ApiKey } from "../../types/components";
export default function ApiKeysPage() {
const [loadingKeys, setLoadingKeys] = useState(true);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const { userData } = useContext(AuthContext);
const [userId, setUserId] = useState("");
const keysList = useRef([]);
useEffect(() => {
getKeys();
}, [userData]);
function getKeys() {
setLoadingKeys(true);
if (userData) {
getApiKey()
.then((keys: [ApiKey]) => {
keysList.current = keys["api_keys"];
setUserId(keys["user_id"]);
setLoadingKeys(false);
})
.catch((error) => {
setLoadingKeys(false);
});
}
}
function resetFilter() {
getKeys();
}
function handleDeleteKey(keys) {
deleteApiKey(keys)
.then((res) => {
resetFilter();
setSuccessData({
title: DEL_KEY_SUCCESS_ALERT,
});
})
.catch((error) => {
setErrorData({
title: DEL_KEY_ERROR_ALERT,
list: [error["response"]["data"]["detail"]],
});
});
}
function lastUsedMessage() {
return (
<div className="text-xs">
<span>
{LAST_USED_SPAN_1}
<br></br> {LAST_USED_SPAN_2}
</span>
</div>
);
}
return (
<>
<Header></Header>
{userData && (
<div className="main-page-panel">
<div className="m-auto flex h-full flex-row justify-center">
<div className="basis-5/6">
<div className="m-auto flex h-full flex-col space-y-8 p-8 ">
<div className="flex items-center justify-between space-y-2">
<div>
<h2 className="text-2xl font-bold tracking-tight">
API keys
</h2>
<p className="text-muted-foreground">
{API_PAGE_PARAGRAPH_1}
<br />
{API_PAGE_PARAGRAPH_2}
</p>
</div>
<div className="flex items-center space-x-2"></div>
</div>
{keysList.current &&
keysList.current.length === 0 &&
!loadingKeys && (
<>
<div className="flex items-center justify-between">
<h2>{API_PAGE_USER_KEYS}</h2>
</div>
</>
)}
<>
{loadingKeys && (
<div>
<strong>Loading...</strong>
</div>
)}
<div
className={
"max-h-[15rem] overflow-scroll overflow-x-hidden rounded-md border-2 bg-muted custom-scroll" +
(loadingKeys ? " border-0" : "")
}
>
{keysList.current &&
keysList.current.length > 0 &&
!loadingKeys && (
<Table className={"table-fixed bg-muted outline-1"}>
<TableHeader
className={
loadingKeys
? "hidden"
: "table-fixed bg-muted outline-1"
}
>
<TableRow>
<TableHead className="h-10">Name</TableHead>
<TableHead className="h-10">Key</TableHead>
<TableHead className="h-10">Created</TableHead>
<TableHead className="flex h-10 items-center">
Last Used
<ShadTooltip
side="top"
content={lastUsedMessage()}
>
<div>
<IconComponent
name="Info"
className="ml-1 h-3 w-3"
/>
</div>
</ShadTooltip>
</TableHead>
<TableHead className="h-10">Total Uses</TableHead>
<TableHead className="h-10 w-[100px] text-right"></TableHead>
</TableRow>
</TableHeader>
{!loadingKeys && (
<TableBody>
{keysList.current.map(
(api_keys: ApiKey, index: number) => (
<TableRow key={index}>
<TableCell className="truncate py-2">
<ShadTooltip content={api_keys.name}>
<span className="cursor-default">
{api_keys.name ? api_keys.name : "-"}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="truncate py-2">
<span className="cursor-default">
{api_keys.api_key}
</span>
</TableCell>
<TableCell className="truncate py-2 ">
<ShadTooltip
side="top"
content={moment(
api_keys.created_at
).format("YYYY-MM-DD HH:mm")}
>
<div>
{moment(api_keys.created_at).format(
"YYYY-MM-DD HH:mm"
)}
</div>
</ShadTooltip>
</TableCell>
<TableCell className="truncate py-2">
<ShadTooltip
side="top"
content={
moment(api_keys.last_used_at).format(
"YYYY-MM-DD HH:mm"
) === "Invalid date"
? "Never"
: moment(
api_keys.last_used_at
).format("YYYY-MM-DD HH:mm")
}
>
<div>
{moment(api_keys.last_used_at).format(
"YYYY-MM-DD HH:mm"
) === "Invalid date"
? "Never"
: moment(
api_keys.last_used_at
).format("YYYY-MM-DD HH:mm")}
</div>
</ShadTooltip>
</TableCell>
<TableCell className="truncate py-2">
{api_keys.total_uses}
</TableCell>
<TableCell className="flex w-[100px] py-2 text-right">
<div className="flex">
<ConfirmationModal
title="Delete"
titleHeader="Delete User"
modalContentTitle="Attention!"
cancelText="Cancel"
confirmationText="Delete"
icon={"UserMinus2"}
data={api_keys.id}
index={index}
onConfirm={(index, keys) => {
handleDeleteKey(keys);
}}
>
<ConfirmationModal.Content>
<span>
Are you sure you want to delete
this key? This action cannot be
undone.
</span>
</ConfirmationModal.Content>
<ConfirmationModal.Trigger>
<IconComponent
name="Trash2"
className="ml-2 h-4 w-4 cursor-pointer"
/>
</ConfirmationModal.Trigger>
</ConfirmationModal>
</div>
</TableCell>
</TableRow>
)
)}
</TableBody>
)}
</Table>
)}
</div>
<div className="flex items-center justify-between">
<div>
<SecretKeyModal
title="Create new secret key"
cancelText="Cancel"
confirmationText="Create secret key"
icon={"Key"}
data={userId}
onCloseModal={getKeys}
>
<Button>
<IconComponent name="Plus" className="mr-1 h-5 w-5" />
Create new secret key
</Button>
</SecretKeyModal>
</div>
</div>
</>
</div>
</div>
</div>
</div>
)}
</>
);
}

View file

@ -36,8 +36,8 @@ import {
} from "../../../../utils/reactflowUtils"; } from "../../../../utils/reactflowUtils";
import ConnectionLineComponent from "../ConnectionLineComponent"; import ConnectionLineComponent from "../ConnectionLineComponent";
import SelectionMenu from "../SelectionMenuComponent"; import SelectionMenu from "../SelectionMenuComponent";
import isWrappedWithClass from "./utils/is-wrapped-with-class";
import getRandomName from "./utils/get-random-name"; import getRandomName from "./utils/get-random-name";
import isWrappedWithClass from "./utils/is-wrapped-with-class";
const nodeTypes = { const nodeTypes = {
genericNode: GenericNode, genericNode: GenericNode,
@ -52,19 +52,19 @@ export default function Page({
}): JSX.Element { }): JSX.Element {
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
const autoSaveCurrentFlow = useFlowsManagerStore( const autoSaveCurrentFlow = useFlowsManagerStore(
(state) => state.autoSaveCurrentFlow, (state) => state.autoSaveCurrentFlow
); );
const types = useTypesStore((state) => state.types); const types = useTypesStore((state) => state.types);
const templates = useTypesStore((state) => state.templates); const templates = useTypesStore((state) => state.templates);
const setFilterEdge = useFlowStore((state) => state.setFilterEdge); const setFilterEdge = useFlowStore((state) => state.setFilterEdge);
const reactFlowWrapper = useRef<HTMLDivElement>(null); const reactFlowWrapper = useRef<HTMLDivElement>(null);
const [showCanvas, setSHowCanvas] = useState( const [showCanvas, setSHowCanvas] = useState(
Object.keys(templates).length > 0 && Object.keys(types).length > 0, Object.keys(templates).length > 0 && Object.keys(types).length > 0
); );
const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance);
const setReactFlowInstance = useFlowStore( const setReactFlowInstance = useFlowStore(
(state) => state.setReactFlowInstance, (state) => state.setReactFlowInstance
); );
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges); const edges = useFlowStore((state) => state.edges);
@ -81,10 +81,10 @@ export default function Page({
const paste = useFlowStore((state) => state.paste); const paste = useFlowStore((state) => state.paste);
const resetFlow = useFlowStore((state) => state.resetFlow); const resetFlow = useFlowStore((state) => state.resetFlow);
const lastCopiedSelection = useFlowStore( const lastCopiedSelection = useFlowStore(
(state) => state.lastCopiedSelection, (state) => state.lastCopiedSelection
); );
const setLastCopiedSelection = useFlowStore( const setLastCopiedSelection = useFlowStore(
(state) => state.setLastCopiedSelection, (state) => state.setLastCopiedSelection
); );
const onConnect = useFlowStore((state) => state.onConnect); const onConnect = useFlowStore((state) => state.onConnect);
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
@ -107,7 +107,7 @@ export default function Page({
clonedSelection!, clonedSelection!,
clonedNodes, clonedNodes,
clonedEdges, clonedEdges,
getRandomName(), getRandomName()
); );
const newGroupNode = generateNodeFromFlow(newFlow, getNodeId); const newGroupNode = generateNodeFromFlow(newFlow, getNodeId);
const newEdges = reconnectEdges(newGroupNode, removedEdges); const newEdges = reconnectEdges(newGroupNode, removedEdges);
@ -115,8 +115,8 @@ export default function Page({
...clonedNodes.filter( ...clonedNodes.filter(
(oldNodes) => (oldNodes) =>
!clonedSelection?.nodes.some( !clonedSelection?.nodes.some(
(selectionNode) => selectionNode.id === oldNodes.id, (selectionNode) => selectionNode.id === oldNodes.id
), )
), ),
newGroupNode, newGroupNode,
]); ]);
@ -126,8 +126,8 @@ export default function Page({
!clonedSelection!.nodes.some( !clonedSelection!.nodes.some(
(selectionNode) => (selectionNode) =>
selectionNode.id === oldEdge.target || selectionNode.id === oldEdge.target ||
selectionNode.id === oldEdge.source, selectionNode.id === oldEdge.source
), )
), ),
...newEdges, ...newEdges,
]); ]);
@ -180,7 +180,7 @@ export default function Page({
{ {
x: position.current.x, x: position.current.x,
y: position.current.y, y: position.current.y,
}, }
); );
} }
if (!isWrappedWithClass(event, "noundo")) { if (!isWrappedWithClass(event, "noundo")) {
@ -276,7 +276,7 @@ export default function Page({
useEffect(() => { useEffect(() => {
setSHowCanvas( setSHowCanvas(
Object.keys(templates).length > 0 && Object.keys(types).length > 0, Object.keys(templates).length > 0 && Object.keys(types).length > 0
); );
}, [templates, types]); }, [templates, types]);
@ -285,7 +285,7 @@ export default function Page({
takeSnapshot(); takeSnapshot();
onConnect(params); onConnect(params);
}, },
[takeSnapshot, onConnect], [takeSnapshot, onConnect]
); );
const onNodeDragStart: NodeDragHandler = useCallback(() => { const onNodeDragStart: NodeDragHandler = useCallback(() => {
@ -326,7 +326,7 @@ export default function Page({
// Extract the data from the drag event and parse it as a JSON object // Extract the data from the drag event and parse it as a JSON object
const data: { type: string; node?: APIClassType } = JSON.parse( const data: { type: string; node?: APIClassType } = JSON.parse(
event.dataTransfer.getData("nodedata"), event.dataTransfer.getData("nodedata")
); );
const newId = getNodeId(data.type); const newId = getNodeId(data.type);
@ -342,7 +342,7 @@ export default function Page({
}; };
paste( paste(
{ nodes: [newNode], edges: [] }, { nodes: [newNode], edges: [] },
{ x: event.clientX, y: event.clientY }, { x: event.clientX, y: event.clientY }
); );
} else if (event.dataTransfer.types.some((types) => types === "Files")) { } else if (event.dataTransfer.types.some((types) => types === "Files")) {
takeSnapshot(); takeSnapshot();
@ -371,7 +371,7 @@ export default function Page({
} }
}, },
// Specify dependencies for useCallback // Specify dependencies for useCallback
[getNodeId, setNodes, takeSnapshot, paste], [getNodeId, setNodes, takeSnapshot, paste]
); );
const onEdgeUpdateStart = useCallback(() => { const onEdgeUpdateStart = useCallback(() => {
@ -387,7 +387,7 @@ export default function Page({
setEdges((els) => updateEdge(oldEdge, newConnection, els)); setEdges((els) => updateEdge(oldEdge, newConnection, els));
} }
}, },
[setEdges], [setEdges]
); );
const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => { const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => {
@ -420,7 +420,7 @@ export default function Page({
(flow: OnSelectionChangeParams): void => { (flow: OnSelectionChangeParams): void => {
setLastSelection(flow); setLastSelection(flow);
}, },
[], []
); );
const onPaneClick = useCallback((flow) => { const onPaneClick = useCallback((flow) => {

View file

@ -5,7 +5,7 @@ import { toTitleCase } from "../../../../../utils/utils";
export default function getRandomName( export default function getRandomName(
retry: number = 0, retry: number = 0,
noSpace: boolean = false, noSpace: boolean = false,
maxRetries: number = 3, maxRetries: number = 3
): string { ): string {
const left: string[] = ADJECTIVES; const left: string[] = ADJECTIVES;
const right: string[] = NOUNS; const right: string[] = NOUNS;

View file

@ -13,7 +13,7 @@ export default function SelectionMenu({
const [disable, setDisable] = useState<boolean>( const [disable, setDisable] = useState<boolean>(
lastSelection && edges.length > 0 lastSelection && edges.length > 0
? validateSelection(lastSelection!, edges).length > 0 ? validateSelection(lastSelection!, edges).length > 0
: false, : false
); );
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isTransitioning, setIsTransitioning] = useState(false); const [isTransitioning, setIsTransitioning] = useState(false);

View file

@ -41,7 +41,7 @@ export default function ExtraSidebar(): JSX.Element {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
function onDragStart( function onDragStart(
event: React.DragEvent<any>, event: React.DragEvent<any>,
data: { type: string; node?: APIClassType }, data: { type: string; node?: APIClassType }
): void { ): void {
//start drag event //start drag event
var crt = event.currentTarget.cloneNode(true); var crt = event.currentTarget.cloneNode(true);
@ -67,7 +67,7 @@ export default function ExtraSidebar(): JSX.Element {
let keys = Object.keys(data[d]).filter( let keys = Object.keys(data[d]).filter(
(nd) => (nd) =>
nd.toLowerCase().includes(e.toLowerCase()) || nd.toLowerCase().includes(e.toLowerCase()) ||
data[d][nd].display_name?.toLowerCase().includes(e.toLowerCase()), data[d][nd].display_name?.toLowerCase().includes(e.toLowerCase())
); );
keys.forEach((element) => { keys.forEach((element) => {
ret[d][element] = data[d][element]; ret[d][element] = data[d][element];
@ -134,7 +134,7 @@ export default function ExtraSidebar(): JSX.Element {
if (filtered.some((x) => x !== "")) { if (filtered.some((x) => x !== "")) {
let keys = Object.keys(dataClone[d]).filter((nd) => let keys = Object.keys(dataClone[d]).filter((nd) =>
filtered.includes(nd), filtered.includes(nd)
); );
Object.keys(dataClone[d]).forEach((element) => { Object.keys(dataClone[d]).forEach((element) => {
if (!keys.includes(element)) { if (!keys.includes(element)) {
@ -171,7 +171,7 @@ export default function ExtraSidebar(): JSX.Element {
if (filtered.some((x) => x !== "")) { if (filtered.some((x) => x !== "")) {
let keys = Object.keys(dataClone[d]).filter((nd) => let keys = Object.keys(dataClone[d]).filter((nd) =>
filtered.includes(nd), filtered.includes(nd)
); );
Object.keys(dataClone[d]).forEach((element) => { Object.keys(dataClone[d]).forEach((element) => {
if (!keys.includes(element)) { if (!keys.includes(element)) {
@ -200,7 +200,7 @@ export default function ExtraSidebar(): JSX.Element {
"extra-side-bar-buttons gap-[4px] text-sm font-semibold", "extra-side-bar-buttons gap-[4px] text-sm font-semibold",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? "button-disable cursor-default text-muted-foreground" ? "button-disable cursor-default text-muted-foreground"
: "", : ""
)} )}
> >
<IconComponent <IconComponent
@ -209,14 +209,14 @@ export default function ExtraSidebar(): JSX.Element {
"-m-0.5 -ml-1 h-6 w-6", "-m-0.5 -ml-1 h-6 w-6",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? "extra-side-bar-save-disable" ? "extra-side-bar-save-disable"
: "", : ""
)} )}
/> />
Share Share
</button> </button>
</ShareModal> </ShareModal>
), ),
[hasApiKey, validApiKey, currentFlow, hasStore], [hasApiKey, validApiKey, currentFlow, hasStore]
); );
const ExportMemo = useMemo( const ExportMemo = useMemo(
@ -227,7 +227,7 @@ export default function ExtraSidebar(): JSX.Element {
</button> </button>
</ExportModal> </ExportModal>
), ),
[], []
); );
const getIcon = useMemo(() => { const getIcon = useMemo(() => {
@ -311,8 +311,8 @@ export default function ExtraSidebar(): JSX.Element {
.sort((a, b) => .sort((a, b) =>
sensitiveSort( sensitiveSort(
dataFilter[SBSectionName][a].display_name, dataFilter[SBSectionName][a].display_name,
dataFilter[SBSectionName][b].display_name, dataFilter[SBSectionName][b].display_name
), )
) )
.map((SBItemName: string, index) => ( .map((SBItemName: string, index) => (
<ShadTooltip <ShadTooltip
@ -356,7 +356,7 @@ export default function ExtraSidebar(): JSX.Element {
</> </>
) : ( ) : (
<div key={index}></div> <div key={index}></div>
), )
)}{" "} )}{" "}
<ParentDisclosureComponent <ParentDisclosureComponent
openDisc={false} openDisc={false}
@ -393,8 +393,8 @@ export default function ExtraSidebar(): JSX.Element {
.sort((a, b) => .sort((a, b) =>
sensitiveSort( sensitiveSort(
dataFilter[SBSectionName][a].display_name, dataFilter[SBSectionName][a].display_name,
dataFilter[SBSectionName][b].display_name, dataFilter[SBSectionName][b].display_name
), )
) )
.map((SBItemName: string, index) => ( .map((SBItemName: string, index) => (
<ShadTooltip <ShadTooltip
@ -468,7 +468,7 @@ export default function ExtraSidebar(): JSX.Element {
</> </>
) : ( ) : (
<div key={index}></div> <div key={index}></div>
), )
)} )}
</ParentDisclosureComponent> </ParentDisclosureComponent>
</div> </div>

View file

@ -10,7 +10,7 @@ import ExtraSidebar from "./components/extraSidebarComponent";
export default function FlowPage({ view }: { view?: boolean }): JSX.Element { export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
const setCurrentFlowId = useFlowsManagerStore( const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId, (state) => state.setCurrentFlowId
); );
const version = useDarkStore((state) => state.version); const version = useDarkStore((state) => state.version);
const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage); const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage);

View file

@ -31,22 +31,22 @@ export default function ComponentsComponent({
const allFlows = useFlowsManagerStore((state) => state.allFlows); const allFlows = useFlowsManagerStore((state) => state.allFlows);
const flowsFromFolder = useFolderStore( const flowsFromFolder = useFolderStore(
(state) => state.selectedFolder?.flows, (state) => state.selectedFolder?.flows
); );
const setSuccessData = useAlertStore((state) => state.setSuccessData); const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const [openDelete, setOpenDelete] = useState(false); const [openDelete, setOpenDelete] = useState(false);
const searchFlowsComponents = useFlowsManagerStore( const searchFlowsComponents = useFlowsManagerStore(
(state) => state.searchFlowsComponents, (state) => state.searchFlowsComponents
); );
const setSelectedFlowsComponentsCards = useFlowsManagerStore( const setSelectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.setSelectedFlowsComponentsCards, (state) => state.setSelectedFlowsComponentsCards
); );
const selectedFlowsComponentsCards = useFlowsManagerStore( const selectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.selectedFlowsComponentsCards, (state) => state.selectedFlowsComponentsCards
); );
const [handleFileDrop] = useFileDrop(uploadFlow, type)!; const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
@ -82,7 +82,7 @@ export default function ComponentsComponent({
f.name.toLowerCase().includes(searchFlowsComponents.toLowerCase()) || f.name.toLowerCase().includes(searchFlowsComponents.toLowerCase()) ||
f.description f.description
.toLowerCase() .toLowerCase()
.includes(searchFlowsComponents.toLowerCase()), .includes(searchFlowsComponents.toLowerCase())
); );
if (searchFlowsComponents === "") { if (searchFlowsComponents === "") {
@ -137,9 +137,9 @@ export default function ComponentsComponent({
selectedFlowsComponentsCards.map((selectedFlow) => selectedFlowsComponentsCards.map((selectedFlow) =>
addFlow( addFlow(
true, true,
allFlows.find((flow) => flow.id === selectedFlow), allFlows.find((flow) => flow.id === selectedFlow)
), )
), )
).then(() => { ).then(() => {
resetFilter(); resetFilter();
getFoldersApi(true); getFoldersApi(true);
@ -180,7 +180,7 @@ export default function ComponentsComponent({
return true; return true;
} }
return false; return false;
}, }
); );
setSelectedFlowsComponentsCards(selectedFlows); setSelectedFlowsComponentsCards(selectedFlows);
@ -215,7 +215,7 @@ export default function ComponentsComponent({
if (type === "all") return allFlows?.length; if (type === "all") return allFlows?.length;
return allFlows?.filter( return allFlows?.filter(
(f) => (f.is_component ?? false) === (type === "component"), (f) => (f.is_component ?? false) === (type === "component")
)?.length; )?.length;
}; };

View file

@ -1,7 +1,7 @@
import { useNavigate } from "react-router-dom";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import NewFlowModal from "../../../../modals/newFlowModal";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router-dom";
import NewFlowModal from "../../../../modals/newFlowModal";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
type EmptyComponentProps = {}; type EmptyComponentProps = {};

View file

@ -1,17 +1,8 @@
import { useState } from "react"; import { useState } from "react";
import IconComponent from "../../../../components/genericIconComponent"; import IconComponent from "../../../../components/genericIconComponent";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "../../../../components/ui/select";
import { Checkbox } from "../../../../components/ui/checkbox";
import { Button } from "../../../../components/ui/button";
import { cn } from "../../../../utils/utils";
import ShadTooltip from "../../../../components/shadTooltipComponent"; import ShadTooltip from "../../../../components/shadTooltipComponent";
import { Checkbox } from "../../../../components/ui/checkbox";
import { cn } from "../../../../utils/utils";
type HeaderComponentProps = { type HeaderComponentProps = {
handleSelectAll: (select) => void; handleSelectAll: (select) => void;
@ -91,7 +82,7 @@ const HeaderComponent = ({
name="Trash2" name="Trash2"
className={cn( className={cn(
"h-5 w-5 text-primary transition-all", "h-5 w-5 text-primary transition-all",
disableFunctions ? "" : "hover:text-destructive", disableFunctions ? "" : "hover:text-destructive"
)} )}
/> />
</button> </button>

View file

@ -1,13 +1,11 @@
import { useState } from "react"; import { useState } from "react";
import { useLocation } from "react-router-dom";
import useAlertStore from "../../../../../../stores/alertStore";
import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore";
import { useFolderStore } from "../../../../../../stores/foldersStore";
import { handleDownloadFolderFn } from "../../../../utils/handle-download-folder";
import InputSearchComponent from "../inputSearchComponent"; import InputSearchComponent from "../inputSearchComponent";
import TabsSearchComponent from "../tabsComponent"; import TabsSearchComponent from "../tabsComponent";
import { Button } from "../../../../../../components/ui/button";
import ForwardedIconComponent from "../../../../../../components/genericIconComponent";
import useAlertStore from "../../../../../../stores/alertStore";
import { handleDownloadFolderFn } from "../../../../utils/handle-download-folder";
import { useFolderStore } from "../../../../../../stores/foldersStore";
import { useLocation } from "react-router-dom";
type HeaderTabsSearchComponentProps = {}; type HeaderTabsSearchComponentProps = {};
@ -22,7 +20,7 @@ const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => {
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const setSearchFlowsComponents = useFlowsManagerStore( const setSearchFlowsComponents = useFlowsManagerStore(
(state) => state.setSearchFlowsComponents, (state) => state.setSearchFlowsComponents
); );
const handleDownloadFolder = () => { const handleDownloadFolder = () => {

View file

@ -1,7 +1,7 @@
import { ChangeEvent, KeyboardEvent } from "react"; import { ChangeEvent, KeyboardEvent } from "react";
import ForwardedIconComponent from "../../../../../../components/genericIconComponent";
import { Input } from "../../../../../../components/ui/input"; import { Input } from "../../../../../../components/ui/input";
import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore";
import ForwardedIconComponent from "../../../../../../components/genericIconComponent";
type InputSearchComponentProps = { type InputSearchComponentProps = {
loading: boolean; loading: boolean;
@ -23,7 +23,7 @@ const InputSearchComponent = ({
const pagePath = window.location.pathname; const pagePath = window.location.pathname;
const allFlows = useFlowsManagerStore((state) => state.allFlows); const allFlows = useFlowsManagerStore((state) => state.allFlows);
const searchFlowsComponents = useFlowsManagerStore( const searchFlowsComponents = useFlowsManagerStore(
(state) => state.searchFlowsComponents, (state) => state.searchFlowsComponents
); );
const disableInputSearch = const disableInputSearch =

View file

@ -16,7 +16,7 @@ import useDropdownOptions from "../../hooks/use-dropdown-options";
export default function HomePage(): JSX.Element { export default function HomePage(): JSX.Element {
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
const setCurrentFlowId = useFlowsManagerStore( const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId, (state) => state.setCurrentFlowId
); );
const location = useLocation(); const location = useLocation();

Some files were not shown because too many files have changed in this diff Show more