Merge branch 'cz/bug/state/zustand' into update_lc
This commit is contained in:
commit
4591824a63
94 changed files with 2443 additions and 3090 deletions
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi import Request, Response, APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlmodel import Session
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ router = APIRouter(tags=["Login"])
|
|||
|
||||
@router.post("/login", response_model=Token)
|
||||
async def login_to_get_access_token(
|
||||
response: Response,
|
||||
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||
db: Session = Depends(get_session),
|
||||
# _: Session = Depends(get_current_active_user)
|
||||
|
|
@ -31,7 +32,10 @@ async def login_to_get_access_token(
|
|||
) from exc
|
||||
|
||||
if user:
|
||||
return create_user_tokens(user_id=user.id, db=db, update_last_login=True)
|
||||
tokens = create_user_tokens(user_id=user.id, db=db, update_last_login=True)
|
||||
response.set_cookie("refresh_token_lf", tokens["refresh_token"], httponly=True, secure=True, samesite="strict")
|
||||
response.set_cookie("access_token_lf", tokens["access_token"], httponly=False, secure=True, samesite="strict")
|
||||
return tokens
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
|
|
@ -41,9 +45,13 @@ async def login_to_get_access_token(
|
|||
|
||||
|
||||
@router.get("/auto_login")
|
||||
async def auto_login(db: Session = Depends(get_session), settings_service=Depends(get_settings_service)):
|
||||
async def auto_login(
|
||||
response: Response, db: Session = Depends(get_session), settings_service=Depends(get_settings_service)
|
||||
):
|
||||
if settings_service.auth_settings.AUTO_LOGIN:
|
||||
return create_user_longterm_token(db)
|
||||
tokens = create_user_longterm_token(db)
|
||||
response.set_cookie("access_token_lf", tokens["access_token"], httponly=False, secure=True, samesite="strict")
|
||||
return tokens
|
||||
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
|
|
@ -55,12 +63,23 @@ async def auto_login(db: Session = Depends(get_session), settings_service=Depend
|
|||
|
||||
|
||||
@router.post("/refresh")
|
||||
async def refresh_token(token: str):
|
||||
async def refresh_token(request: Request, response: Response):
|
||||
token = request.cookies.get("refresh_token_lf")
|
||||
if token:
|
||||
return create_refresh_token(token)
|
||||
tokens = create_refresh_token(token)
|
||||
response.set_cookie("refresh_token_lf", tokens["refresh_token"], httponly=True, secure=True, samesite="strict")
|
||||
response.set_cookie("access_token_lf", tokens["access_token"], httponly=False, secure=True, samesite="strict")
|
||||
return tokens
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid refresh token",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/logout")
|
||||
async def logout(response: Response):
|
||||
response.delete_cookie("refresh_token_lf")
|
||||
response.delete_cookie("access_token_lf")
|
||||
return {"message": "Logout successful"}
|
||||
|
|
|
|||
|
|
@ -15,29 +15,21 @@ class VectaraSelfQueryRetriverComponent(CustomComponent):
|
|||
|
||||
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
||||
description: str = "Implementation of Vectara Self Query Retriever"
|
||||
documentation = (
|
||||
"https://python.langchain.com/docs/integrations/retrievers/self_query/vectara_self_query"
|
||||
)
|
||||
documentation = "https://python.langchain.com/docs/integrations/retrievers/self_query/vectara_self_query"
|
||||
beta = True
|
||||
|
||||
field_config = {
|
||||
"code": {"show": True},
|
||||
"vectorstore": {
|
||||
"display_name": "Vector Store",
|
||||
"info": "Input Vectara Vectore Store"
|
||||
},
|
||||
"llm": {
|
||||
"display_name": "LLM",
|
||||
"info": "For self query retriever"
|
||||
},
|
||||
"document_content_description":{
|
||||
"display_name": "Document Content Description",
|
||||
"vectorstore": {"display_name": "Vector Store", "info": "Input Vectara Vectore Store"},
|
||||
"llm": {"display_name": "LLM", "info": "For self query retriever"},
|
||||
"document_content_description": {
|
||||
"display_name": "Document Content Description",
|
||||
"info": "For self query retriever",
|
||||
},
|
||||
},
|
||||
"metadata_field_info": {
|
||||
"display_name": "Metadata Field Info",
|
||||
"info": "Each metadata field info is a string in the form of key value pair dictionary containing additional search metadata.\nExample input: {\"name\":\"speech\",\"description\":\"what name of the speech\",\"type\":\"string or list[string]\"}.\nThe keys should remain constant(name, description, type)",
|
||||
},
|
||||
"display_name": "Metadata Field Info",
|
||||
"info": 'Each metadata field info is a string in the form of key value pair dictionary containing additional search metadata.\nExample input: {"name":"speech","description":"what name of the speech","type":"string or list[string]"}.\nThe keys should remain constant(name, description, type)',
|
||||
},
|
||||
}
|
||||
|
||||
def build(
|
||||
|
|
@ -47,24 +39,19 @@ class VectaraSelfQueryRetriverComponent(CustomComponent):
|
|||
llm: BaseLanguageModel,
|
||||
metadata_field_info: List[str],
|
||||
) -> BaseRetriever:
|
||||
|
||||
metadata_field_obj = []
|
||||
|
||||
for meta in metadata_field_info:
|
||||
meta_obj = json.loads(meta)
|
||||
if 'name' not in meta_obj or 'description' not in meta_obj or 'type' not in meta_obj :
|
||||
raise Exception('Incorrect metadata field info format.')
|
||||
if "name" not in meta_obj or "description" not in meta_obj or "type" not in meta_obj:
|
||||
raise Exception("Incorrect metadata field info format.")
|
||||
attribute_info = AttributeInfo(
|
||||
name = meta_obj['name'],
|
||||
description = meta_obj['description'],
|
||||
type = meta_obj['type'],
|
||||
name=meta_obj["name"],
|
||||
description=meta_obj["description"],
|
||||
type=meta_obj["type"],
|
||||
)
|
||||
metadata_field_obj.append(attribute_info)
|
||||
|
||||
return SelfQueryRetriever.from_llm(
|
||||
llm,
|
||||
vectorstore,
|
||||
document_content_description,
|
||||
metadata_field_obj,
|
||||
verbose=True
|
||||
)
|
||||
llm, vectorstore, document_content_description, metadata_field_obj, verbose=True
|
||||
)
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flows" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
@ -338,7 +338,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flows" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
@ -392,7 +392,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flows" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
@ -446,7 +446,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flow/2920dde2-5c24-4fe0-9c06-ef86b5a16a99" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
@ -500,7 +500,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flow/2920dde2-5c24-4fe0-9c06-ef86b5a16a99" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
@ -554,7 +554,7 @@
|
|||
{ "name": "Accept-Language", "value": "en-US,en;q=0.9" },
|
||||
{ "name": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20" },
|
||||
{ "name": "Connection", "value": "keep-alive" },
|
||||
{ "name": "Cookie", "value": "access_tkn_lflw=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Cookie", "value": "access_token_lf=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkMjUzYmZiYS02MzY4LTQ0ZGMtODVmNy0wZDZkYTllNDU5NjgiLCJleHAiOjE3MzM4NTY4OTh9.5MFFb0JCck3ITSKXbxhwO9yAscnXcwXNTV70ZYBRB20; refresh_tkn_lflw=auto" },
|
||||
{ "name": "Host", "value": "localhost:3000" },
|
||||
{ "name": "Referer", "value": "http://localhost:3000/flow/2920dde2-5c24-4fe0-9c06-ef86b5a16a99" },
|
||||
{ "name": "Sec-Fetch-Dest", "value": "empty" },
|
||||
|
|
|
|||
55
src/frontend/package-lock.json
generated
55
src/frontend/package-lock.json
generated
|
|
@ -13,6 +13,7 @@
|
|||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@mui/material": "^5.14.7",
|
||||
"@preact/signals-react": "^2.0.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
|
|
@ -71,7 +72,8 @@
|
|||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^2.1.4",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.38.0",
|
||||
|
|
@ -1465,6 +1467,31 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@preact/signals-core": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.1.tgz",
|
||||
"integrity": "sha512-dE6f+WCX5ZUDwXzUIWNMhhglmuLpqJhuy3X3xHrhZYI0Hm2LyQwOu0l9mdPiWrVNsE+Q7txOnJPgtIqHCYoBVA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/@preact/signals-react": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.0.0.tgz",
|
||||
"integrity": "sha512-tMVi2SXFXlojaiPNWa8dlYaidR/XvEgMSp+iymKJgMssBM/QVtUQrodKZek1BJju+dkVHiyeuQHmkuLOI9oyNw==",
|
||||
"dependencies": {
|
||||
"@preact/signals-core": "^1.5.1",
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0 || 17.x || 18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
|
||||
|
|
@ -11719,9 +11746,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.4.6",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.6.tgz",
|
||||
"integrity": "sha512-Rb16eW55gqL4W2XZpJh0fnrATxYEG3Apl2gfHTyDSE965x/zxslTikpNch0JgNjJA9zK6gEFW8Fl6d1rTZaqgg==",
|
||||
"version": "4.4.7",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz",
|
||||
"integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "1.2.0"
|
||||
},
|
||||
|
|
@ -12606,6 +12633,20 @@
|
|||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
|
||||
},
|
||||
"@preact/signals-core": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.1.tgz",
|
||||
"integrity": "sha512-dE6f+WCX5ZUDwXzUIWNMhhglmuLpqJhuy3X3xHrhZYI0Hm2LyQwOu0l9mdPiWrVNsE+Q7txOnJPgtIqHCYoBVA=="
|
||||
},
|
||||
"@preact/signals-react": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.0.0.tgz",
|
||||
"integrity": "sha512-tMVi2SXFXlojaiPNWa8dlYaidR/XvEgMSp+iymKJgMssBM/QVtUQrodKZek1BJju+dkVHiyeuQHmkuLOI9oyNw==",
|
||||
"requires": {
|
||||
"@preact/signals-core": "^1.5.1",
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@radix-ui/number": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
|
||||
|
|
@ -19291,9 +19332,9 @@
|
|||
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="
|
||||
},
|
||||
"zustand": {
|
||||
"version": "4.4.6",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.6.tgz",
|
||||
"integrity": "sha512-Rb16eW55gqL4W2XZpJh0fnrATxYEG3Apl2gfHTyDSE965x/zxslTikpNch0JgNjJA9zK6gEFW8Fl6d1rTZaqgg==",
|
||||
"version": "4.4.7",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz",
|
||||
"integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==",
|
||||
"requires": {
|
||||
"use-sync-external-store": "1.2.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@mui/material": "^5.14.7",
|
||||
"@preact/signals-react": "^2.0.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
|
|
@ -66,7 +67,8 @@
|
|||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^2.1.4",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"scripts": {
|
||||
"dev:docker": "vite --host 0.0.0.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import _ from "lodash";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import "reactflow/dist/style.css";
|
||||
import "./App.css";
|
||||
|
||||
|
|
@ -15,37 +14,27 @@ import {
|
|||
FETCH_ERROR_DESCRIPION,
|
||||
FETCH_ERROR_MESSAGE,
|
||||
} from "./constants/constants";
|
||||
import { alertContext } from "./contexts/alertContext";
|
||||
import { FlowsContext } from "./contexts/flowsContext";
|
||||
import { locationContext } from "./contexts/locationContext";
|
||||
import { typesContext } from "./contexts/typesContext";
|
||||
import { AuthContext } from "./contexts/authContext";
|
||||
import { getHealth } from "./controllers/API";
|
||||
import Router from "./routes";
|
||||
import useAlertStore from "./stores/alertStore";
|
||||
import { useDarkStore } from "./stores/darkStore";
|
||||
import useFlowsManagerStore from "./stores/flowsManagerStore";
|
||||
import { useTypesStore } from "./stores/typesStore";
|
||||
|
||||
export default function App() {
|
||||
let { setCurrent, setShowSideBar, setIsStackedOpen } =
|
||||
useContext(locationContext);
|
||||
let location = useLocation();
|
||||
useEffect(() => {
|
||||
setCurrent(location.pathname.replace(/\/$/g, "").split("/"));
|
||||
setShowSideBar(true);
|
||||
setIsStackedOpen(true);
|
||||
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
|
||||
const { hardReset } = useContext(FlowsContext);
|
||||
|
||||
const {
|
||||
errorData,
|
||||
errorOpen,
|
||||
setErrorOpen,
|
||||
noticeData,
|
||||
noticeOpen,
|
||||
setNoticeOpen,
|
||||
successData,
|
||||
successOpen,
|
||||
setSuccessOpen,
|
||||
loading,
|
||||
} = useContext(alertContext);
|
||||
const navigate = useNavigate();
|
||||
const { fetchError } = useContext(typesContext);
|
||||
const errorData = useAlertStore((state) => state.errorData);
|
||||
const errorOpen = useAlertStore((state) => state.errorOpen);
|
||||
const setErrorOpen = useAlertStore((state) => state.setErrorOpen);
|
||||
const noticeData = useAlertStore((state) => state.noticeData);
|
||||
const noticeOpen = useAlertStore((state) => state.noticeOpen);
|
||||
const setNoticeOpen = useAlertStore((state) => state.setNoticeOpen);
|
||||
const successData = useAlertStore((state) => state.successData);
|
||||
const successOpen = useAlertStore((state) => state.successOpen);
|
||||
const setSuccessOpen = useAlertStore((state) => state.setSuccessOpen);
|
||||
const loading = useAlertStore((state) => state.loading);
|
||||
const [fetchError, setFetchError] = useState(false);
|
||||
|
||||
// Initialize state variable for the list of alerts
|
||||
const [alertsList, setAlertsList] = useState<
|
||||
|
|
@ -131,28 +120,60 @@ export default function App() {
|
|||
);
|
||||
};
|
||||
|
||||
const { isAuthenticated } = useContext(AuthContext);
|
||||
const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows);
|
||||
const getTypes = useTypesStore((state) => state.getTypes);
|
||||
const refreshVersion = useDarkStore((state) => state.refreshVersion);
|
||||
const refreshStars = useDarkStore((state) => state.refreshStars);
|
||||
|
||||
useEffect(() => {
|
||||
refreshStars();
|
||||
refreshVersion();
|
||||
|
||||
// If the user is authenticated, fetch the types. This code is important to check if the user is auth because of the execution order of the useEffect hooks.
|
||||
if (isAuthenticated === true) {
|
||||
// get data from db
|
||||
getTypes().then(() => {
|
||||
refreshFlows();
|
||||
});
|
||||
}
|
||||
}, [isAuthenticated]);
|
||||
|
||||
useEffect(() => {
|
||||
// Timer to call getHealth every 5 seconds
|
||||
const timer = setInterval(() => {
|
||||
getHealth()
|
||||
.then(() => {
|
||||
if (fetchError) setFetchError(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setFetchError(true);
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
// Clean up the timer on component unmount
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
//need parent component with width and height
|
||||
<div className="flex h-full flex-col">
|
||||
<ErrorBoundary
|
||||
onReset={() => {
|
||||
window.localStorage.removeItem("tabsData");
|
||||
window.localStorage.clear();
|
||||
hardReset();
|
||||
window.location.href = window.location.href;
|
||||
// any reset function
|
||||
}}
|
||||
FallbackComponent={CrashErrorComponent}
|
||||
>
|
||||
{loading ? (
|
||||
{fetchError ? (
|
||||
<FetchErrorComponent
|
||||
description={FETCH_ERROR_DESCRIPION}
|
||||
message={FETCH_ERROR_MESSAGE}
|
||||
></FetchErrorComponent>
|
||||
) : loading ? (
|
||||
<div className="loading-page-panel">
|
||||
{fetchError ? (
|
||||
<FetchErrorComponent
|
||||
description={FETCH_ERROR_DESCRIPION}
|
||||
message={FETCH_ERROR_MESSAGE}
|
||||
></FetchErrorComponent>
|
||||
) : (
|
||||
<LoadingComponent remSize={50} />
|
||||
)}
|
||||
<LoadingComponent remSize={50} />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
import { cloneDeep } from "lodash";
|
||||
import React, {
|
||||
ReactNode,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
|
||||
import React, { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { Handle, Position } from "reactflow";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import CodeAreaComponent from "../../../../components/codeAreaComponent";
|
||||
import DictComponent from "../../../../components/dictComponent";
|
||||
|
|
@ -26,16 +20,15 @@ import {
|
|||
LANGFLOW_SUPPORTED_TYPES,
|
||||
TOOLTIP_EMPTY,
|
||||
} from "../../../../constants/constants";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||
import { postCustomComponentUpdate } from "../../../../controllers/API";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
import useFlowStore from "../../../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
||||
import { useTypesStore } from "../../../../stores/typesStore";
|
||||
import { APIClassType } from "../../../../types/api";
|
||||
import { ParameterComponentType } from "../../../../types/components";
|
||||
import { NodeDataType } from "../../../../types/flow";
|
||||
import {
|
||||
cleanEdges,
|
||||
convertObjToArray,
|
||||
convertValuesToNumbers,
|
||||
hasDuplicateKeys,
|
||||
|
|
@ -68,47 +61,27 @@ export default function ParameterComponent({
|
|||
const ref = useRef<HTMLDivElement>(null);
|
||||
const refHtml = useRef<HTMLDivElement & ReactNode>(null);
|
||||
const infoHtml = useRef<HTMLDivElement & ReactNode>(null);
|
||||
const { setErrorData, modalContextOpen } = useContext(alertContext);
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const [position, setPosition] = useState(0);
|
||||
const { setTabsState, tabId, flows, tabsState, updateFlow } =
|
||||
useContext(FlowsContext);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
|
||||
const [dataRef, setDataRef] = useState(data);
|
||||
|
||||
const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null;
|
||||
|
||||
// Update component position
|
||||
useEffect(() => {
|
||||
if (ref.current && ref.current.offsetTop && ref.current.clientHeight) {
|
||||
setPosition(ref.current.offsetTop + ref.current.clientHeight / 2);
|
||||
updateNodeInternals(data.id);
|
||||
}
|
||||
}, [data.id, ref, ref.current, ref.current?.offsetTop, updateNodeInternals]);
|
||||
|
||||
useEffect(() => {
|
||||
updateNodeInternals(data.id);
|
||||
}, [data.id, position, updateNodeInternals]);
|
||||
const flow = currentFlow?.data?.nodes ?? null;
|
||||
|
||||
const groupedEdge = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
setDataRef(data);
|
||||
}, [modalContextOpen]);
|
||||
const setFilterEdge = useTypesStore((state) => state.setFilterEdge);
|
||||
|
||||
const { reactFlowInstance, setFilterEdge } = useContext(typesContext);
|
||||
let disabled =
|
||||
reactFlowInstance
|
||||
?.getEdges()
|
||||
.some(
|
||||
(edge) =>
|
||||
edge.targetHandle ===
|
||||
scapedJSONStringfy(proxy ? { ...id, proxy } : id)
|
||||
) ?? false;
|
||||
edges.some(
|
||||
(edge) =>
|
||||
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id)
|
||||
) ?? false;
|
||||
|
||||
const { data: myData } = useContext(typesContext);
|
||||
const myData = useTypesStore((state) => state.data);
|
||||
|
||||
const { takeSnapshot } = useContext(undoRedoContext);
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
|
||||
const handleUpdateValues = async (name: string, data: NodeDataType) => {
|
||||
const code = data.node?.template["code"]?.value;
|
||||
|
|
@ -133,68 +106,46 @@ export default function ParameterComponent({
|
|||
if (data.node!.template[name].value !== newValue) {
|
||||
takeSnapshot();
|
||||
}
|
||||
data.node!.template[name].value = newValue;
|
||||
updateNodeInternals(data.id);
|
||||
|
||||
setDataRef((old) => {
|
||||
let newData = cloneDeep(old);
|
||||
newData.node!.template[name].value = newValue;
|
||||
return newData;
|
||||
data.node!.template[name].value = newValue; // necessary to enable ctrl+z inside the input
|
||||
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
|
||||
newNode.data.node.template[name].value = newValue;
|
||||
|
||||
return newNode;
|
||||
});
|
||||
|
||||
// Set state to pending
|
||||
//@ts-ignore
|
||||
if (data.node!.template[name].value !== newValue) {
|
||||
const tabs = cloneDeep(tabsState);
|
||||
tabs[tabId].isPending = false;
|
||||
tabs[tabId].formKeysData = tabsState[tabId].formKeysData;
|
||||
setTabsState({
|
||||
...tabs,
|
||||
});
|
||||
}
|
||||
renderTooltips();
|
||||
};
|
||||
|
||||
const handleNodeClass = (newNodeClass: APIClassType, code?: string): void => {
|
||||
if (!data.node) return;
|
||||
if (data.node!.template[name].value !== newNodeClass.template[name].value) {
|
||||
if (data.node!.template[name].value !== code) {
|
||||
takeSnapshot();
|
||||
}
|
||||
data.node! = {
|
||||
...newNodeClass,
|
||||
description: newNodeClass.description ?? data.node!.description,
|
||||
display_name: newNodeClass.display_name ?? data.node!.display_name,
|
||||
};
|
||||
data.node!.template[name].value = code;
|
||||
updateNodeInternals(data.id);
|
||||
// Set state to pending
|
||||
//@ts-ignore
|
||||
if (data.node!.template[name].value !== code) {
|
||||
const tabs = cloneDeep(tabsState);
|
||||
tabs[tabId].isPending = false;
|
||||
tabs[tabId].formKeysData = tabsState[tabId].formKeysData;
|
||||
setTabsState({
|
||||
...tabs,
|
||||
});
|
||||
}
|
||||
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
node: newNodeClass,
|
||||
description: newNodeClass.description ?? data.node!.description,
|
||||
display_name: newNodeClass.display_name ?? data.node!.display_name,
|
||||
};
|
||||
|
||||
newNode.data.node.template[name].value = code;
|
||||
|
||||
return newNode;
|
||||
});
|
||||
|
||||
renderTooltips();
|
||||
let flow = flows.find((flow) => flow.id === tabId);
|
||||
setTimeout(() => {
|
||||
//timeout necessary because ReactFlow updates are not async
|
||||
if (reactFlowInstance && flow && flow.data) {
|
||||
cleanEdges({
|
||||
flow: {
|
||||
edges: flow.data!.edges,
|
||||
nodes: flow.data!.nodes,
|
||||
},
|
||||
updateEdge: (edge) => {
|
||||
reactFlowInstance.setEdges(edge);
|
||||
updateNodeInternals(data.id);
|
||||
},
|
||||
});
|
||||
updateFlow(flow);
|
||||
}
|
||||
}, 50);
|
||||
};
|
||||
|
||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||
|
|
@ -323,7 +274,7 @@ export default function ParameterComponent({
|
|||
: scapedJSONStringfy(id)
|
||||
}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection, reactFlowInstance!)
|
||||
isValidConnection(connection, nodes, edges)
|
||||
}
|
||||
className={classNames(
|
||||
left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ",
|
||||
|
|
@ -331,7 +282,6 @@ export default function ParameterComponent({
|
|||
)}
|
||||
style={{
|
||||
borderColor: color,
|
||||
top: position,
|
||||
}}
|
||||
onClick={() => {
|
||||
setFilterEdge(groupedEdge.current);
|
||||
|
|
@ -344,7 +294,7 @@ export default function ParameterComponent({
|
|||
) : (
|
||||
<div
|
||||
ref={ref}
|
||||
className="mt-1 flex w-full flex-wrap items-center justify-between bg-muted px-5 py-2"
|
||||
className="relative mt-1 flex w-full flex-wrap items-center justify-between bg-muted px-5 py-2"
|
||||
>
|
||||
<>
|
||||
<div
|
||||
|
|
@ -396,7 +346,7 @@ export default function ParameterComponent({
|
|||
: scapedJSONStringfy(id)
|
||||
}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection, reactFlowInstance!)
|
||||
isValidConnection(connection, nodes, edges)
|
||||
}
|
||||
className={classNames(
|
||||
left ? "-ml-0.5 " : "-mr-0.5 ",
|
||||
|
|
@ -404,7 +354,6 @@ export default function ParameterComponent({
|
|||
)}
|
||||
style={{
|
||||
borderColor: color,
|
||||
top: position,
|
||||
}}
|
||||
onClick={() => {
|
||||
setFilterEdge(groupedEdge.current);
|
||||
|
|
@ -454,9 +403,7 @@ export default function ParameterComponent({
|
|||
id={"toggle-" + index}
|
||||
disabled={disabled}
|
||||
enabled={data.node?.template[name].value ?? false}
|
||||
setEnabled={(isEnabled) => {
|
||||
handleOnNewValue(isEnabled);
|
||||
}}
|
||||
setEnabled={handleOnNewValue}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -558,10 +505,7 @@ export default function ParameterComponent({
|
|||
}
|
||||
: data.node!.template[name].value
|
||||
}
|
||||
onChange={(newValue) => {
|
||||
data.node!.template[name].value = newValue;
|
||||
handleOnNewValue(newValue);
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
id="div-dict-input"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -571,15 +515,14 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
editNode={false}
|
||||
value={
|
||||
dataRef.node!.template[name].value?.length === 0 ||
|
||||
!dataRef.node!.template[name].value
|
||||
data.node!.template[name].value?.length === 0 ||
|
||||
!data.node!.template[name].value
|
||||
? [{ "": "" }]
|
||||
: convertObjToArray(dataRef.node!.template[name].value)
|
||||
: convertObjToArray(data.node!.template[name].value)
|
||||
}
|
||||
duplicateKey={errorDuplicateKey}
|
||||
onChange={(newValue) => {
|
||||
const valueToNumbers = convertValuesToNumbers(newValue);
|
||||
data.node!.template[name].value = valueToNumbers;
|
||||
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
|
||||
handleOnNewValue(valueToNumbers);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
import { useContext, useEffect, useState } from "react";
|
||||
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
|
||||
import { useEffect, useState } from "react";
|
||||
import { NodeToolbar } from "reactflow";
|
||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||
import Tooltip from "../../components/TooltipComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import InputComponent from "../../components/inputComponent";
|
||||
import { Textarea } from "../../components/ui/textarea";
|
||||
import { priorityFields } from "../../constants/constants";
|
||||
import { useSSE } from "../../contexts/SSEContext";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../contexts/flowsContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { undoRedoContext } from "../../contexts/undoRedoContext";
|
||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
import { useTypesStore } from "../../stores/typesStore";
|
||||
import { validationStatusType } from "../../types/components";
|
||||
import { NodeDataType } from "../../types/flow";
|
||||
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||
|
|
@ -30,11 +28,9 @@ export default function GenericNode({
|
|||
xPos: number;
|
||||
yPos: number;
|
||||
}): JSX.Element {
|
||||
const { updateFlow, flows, tabId, saveCurrentFlow } =
|
||||
useContext(FlowsContext);
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } =
|
||||
useContext(typesContext);
|
||||
const types = useTypesStore((state) => state.types);
|
||||
const deleteNode = useFlowStore((state) => state.deleteNode);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
|
||||
const [inputName, setInputName] = useState(false);
|
||||
const [nodeName, setNodeName] = useState(data.node!.display_name);
|
||||
|
|
@ -46,9 +42,8 @@ export default function GenericNode({
|
|||
useState<validationStatusType | null>(null);
|
||||
const [handles, setHandles] = useState<boolean[] | []>([]);
|
||||
let numberOfInputs: boolean[] = [];
|
||||
const { modalContextOpen } = useContext(alertContext);
|
||||
|
||||
const { takeSnapshot } = useContext(undoRedoContext);
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
|
||||
function countHandles(): void {
|
||||
numberOfInputs = Object.keys(data.node!.template)
|
||||
|
|
@ -84,7 +79,8 @@ export default function GenericNode({
|
|||
}, [data, data.node]);
|
||||
|
||||
// State for outline color
|
||||
const { sseData, isBuilding } = useSSE();
|
||||
const sseData = useFlowStore((state) => state.sseData);
|
||||
const isBuilding = useFlowStore((state) => state.isBuilding);
|
||||
|
||||
useEffect(() => {
|
||||
setNodeDescription(data.node!.description);
|
||||
|
|
@ -118,10 +114,12 @@ export default function GenericNode({
|
|||
deleteNode={(id) => {
|
||||
takeSnapshot();
|
||||
deleteNode(id);
|
||||
saveCurrentFlow();
|
||||
}}
|
||||
setShowNode={(show: boolean) => {
|
||||
data.showNode = show;
|
||||
setNode(data.id, (old) => ({
|
||||
...old,
|
||||
data: { ...old.data, showNode: show },
|
||||
}));
|
||||
}}
|
||||
numberOfHandles={handles}
|
||||
showNode={showNode}
|
||||
|
|
@ -173,8 +171,16 @@ export default function GenericNode({
|
|||
setInputName(false);
|
||||
if (nodeName.trim() !== "") {
|
||||
setNodeName(nodeName);
|
||||
data.node!.display_name = nodeName;
|
||||
updateNodeInternals(data.id);
|
||||
setNode(data.id, (old) => ({
|
||||
...old,
|
||||
data: {
|
||||
...old.data,
|
||||
node: {
|
||||
...old.data.node,
|
||||
display_name: nodeName,
|
||||
},
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
setNodeName(data.node!.display_name);
|
||||
}
|
||||
|
|
@ -380,8 +386,16 @@ export default function GenericNode({
|
|||
onBlur={() => {
|
||||
setInputDescription(false);
|
||||
setNodeDescription(nodeDescription);
|
||||
data.node!.description = nodeDescription;
|
||||
updateNodeInternals(data.id);
|
||||
setNode(data.id, (old) => ({
|
||||
...old,
|
||||
data: {
|
||||
...old.data,
|
||||
node: {
|
||||
...old.data.node,
|
||||
description: nodeDescription,
|
||||
},
|
||||
},
|
||||
}));
|
||||
}}
|
||||
value={nodeDescription}
|
||||
onChange={(e) => setNodeDescription(e.target.value)}
|
||||
|
|
@ -395,8 +409,16 @@ export default function GenericNode({
|
|||
) {
|
||||
setInputDescription(false);
|
||||
setNodeDescription(nodeDescription);
|
||||
data.node!.description = nodeDescription;
|
||||
updateNodeInternals(data.id);
|
||||
setNode(data.id, (old) => ({
|
||||
...old,
|
||||
data: {
|
||||
...old.data,
|
||||
node: {
|
||||
...old.data.node,
|
||||
description: nodeDescription,
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,27 @@
|
|||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "../../components/ui/popover";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import { AlertDropdownType } from "../../types/alerts";
|
||||
import SingleAlert from "./components/singleAlertComponent";
|
||||
|
||||
export default function AlertDropdown({
|
||||
children,
|
||||
}: AlertDropdownType): JSX.Element {
|
||||
const {
|
||||
notificationList,
|
||||
clearNotificationList,
|
||||
removeFromNotificationList,
|
||||
setNotificationCenter,
|
||||
} = useContext(alertContext);
|
||||
const notificationList = useAlertStore((state) => state.notificationList);
|
||||
const clearNotificationList = useAlertStore(
|
||||
(state) => state.clearNotificationList
|
||||
);
|
||||
const removeFromNotificationList = useAlertStore(
|
||||
(state) => state.removeFromNotificationList
|
||||
);
|
||||
const setNotificationCenter = useAlertStore(
|
||||
(state) => state.setNotificationCenter
|
||||
);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,16 @@
|
|||
import { useContext, useEffect } from "react";
|
||||
import { useContext } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
|
||||
export const ProtectedAdminRoute = ({ children }) => {
|
||||
const {
|
||||
isAdmin,
|
||||
isAuthenticated,
|
||||
logout,
|
||||
getAuthentication,
|
||||
userData,
|
||||
autoLogin,
|
||||
} = useContext(AuthContext);
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated && !getAuthentication()) {
|
||||
window.location.replace("/login");
|
||||
logout();
|
||||
}
|
||||
}, [isAuthenticated, getAuthentication, logout, userData]);
|
||||
const { isAdmin, isAuthenticated, logout, userData, autoLogin } =
|
||||
useContext(AuthContext);
|
||||
|
||||
if (!isAuthenticated && !getAuthentication()) {
|
||||
return <Navigate to="/login" replace />;
|
||||
}
|
||||
|
||||
if ((userData && !isAdmin) || autoLogin) {
|
||||
if (!isAuthenticated) {
|
||||
logout();
|
||||
} else if ((userData && !isAdmin) || autoLogin) {
|
||||
return <Navigate to="/" replace />;
|
||||
} else {
|
||||
return children;
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import { useContext } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
|
||||
export const ProtectedRoute = ({ children }) => {
|
||||
const { isAuthenticated, logout, getAuthentication } =
|
||||
useContext(AuthContext);
|
||||
if (!isAuthenticated && !getAuthentication()) {
|
||||
const { isAuthenticated, logout } = useContext(AuthContext);
|
||||
if (!isAuthenticated) {
|
||||
logout();
|
||||
return <Navigate to="/login" replace />;
|
||||
} else {
|
||||
return children;
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { Navigate } from "react-router-dom";
|
|||
import { AuthContext } from "../../contexts/authContext";
|
||||
|
||||
export const ProtectedLoginRoute = ({ children }) => {
|
||||
const { getAuthentication, autoLogin } = useContext(AuthContext);
|
||||
const { isAuthenticated, autoLogin } = useContext(AuthContext);
|
||||
|
||||
if (autoLogin === true) {
|
||||
window.location.replace("/");
|
||||
return <Navigate to="/" replace />;
|
||||
}
|
||||
|
||||
if (getAuthentication()) {
|
||||
if (isAuthenticated) {
|
||||
window.location.replace("/");
|
||||
return <Navigate to="/" replace />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useContext, useEffect, useState } from "react";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../contexts/flowsContext";
|
||||
import { StoreContext } from "../../contexts/storeContext";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getComponent, postLikeComponent } from "../../controllers/API";
|
||||
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
import { useStoreStore } from "../../stores/storeStore";
|
||||
import { storeComponent } from "../../types/store";
|
||||
import cloneFLowWithParent from "../../utils/storeUtils";
|
||||
import { cn } from "../../utils/utils";
|
||||
|
|
@ -32,9 +32,10 @@ export default function CollectionCardComponent({
|
|||
button?: JSX.Element;
|
||||
onDelete?: () => void;
|
||||
}) {
|
||||
const { addFlow } = useContext(FlowsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const { setValidApiKey } = useContext(StoreContext);
|
||||
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const setValidApiKey = useStoreStore((state) => state.updateValidApiKey);
|
||||
const isStore = false;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingLike, setLoadingLike] = useState(false);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
import { Transition } from "@headlessui/react";
|
||||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import Loading from "../../../components/ui/loading";
|
||||
import { useSSE } from "../../../contexts/SSEContext";
|
||||
import { alertContext } from "../../../contexts/alertContext";
|
||||
import { typesContext } from "../../../contexts/typesContext";
|
||||
import { postBuildInit } from "../../../controllers/API";
|
||||
import { FlowType } from "../../../types/flow";
|
||||
|
||||
import { FlowsContext } from "../../../contexts/flowsContext";
|
||||
import useAlertStore from "../../../stores/alertStore";
|
||||
import useFlowStore from "../../../stores/flowStore";
|
||||
import { parsedDataType } from "../../../types/components";
|
||||
import { FlowsState } from "../../../types/tabs";
|
||||
import { validateNodes } from "../../../utils/reactflowUtils";
|
||||
import RadialProgressComponent from "../../RadialProgress";
|
||||
import IconComponent from "../../genericIconComponent";
|
||||
|
|
@ -24,11 +21,15 @@ export default function BuildTrigger({
|
|||
setIsBuilt: any;
|
||||
isBuilt: boolean;
|
||||
}): JSX.Element {
|
||||
const { updateSSEData, isBuilding, setIsBuilding, sseData } = useSSE();
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const { setTabsState, saveFlow } = useContext(FlowsContext);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const [isIconTouched, setIsIconTouched] = useState(false);
|
||||
const updateSSEData = useFlowStore((state) => state.updateSSEData);
|
||||
const isBuilding = useFlowStore((state) => state.isBuilding);
|
||||
const setIsBuilding = useFlowStore((state) => state.setIsBuilding);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setFlowState = useFlowStore((state) => state.setFlowState);
|
||||
|
||||
const eventClick = isBuilding ? "pointer-events-none" : "";
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
|
|
@ -37,10 +38,7 @@ export default function BuildTrigger({
|
|||
if (isBuilding) {
|
||||
return;
|
||||
}
|
||||
const errors = validateNodes(
|
||||
reactFlowInstance!.getNodes(),
|
||||
reactFlowInstance!.getEdges()
|
||||
);
|
||||
const errors = validateNodes(nodes, edges);
|
||||
if (errors.length > 0) {
|
||||
setErrorData({
|
||||
title: "Oops! Looks like you missed something",
|
||||
|
|
@ -76,7 +74,6 @@ export default function BuildTrigger({
|
|||
}
|
||||
async function streamNodeData(flow: FlowType) {
|
||||
// Step 1: Make a POST request to send the flow data and receive a unique session ID
|
||||
const id = saveFlow(flow, true);
|
||||
const response = await postBuildInit(flow);
|
||||
const { flowId } = response.data;
|
||||
// Step 2: Use the session ID to establish an SSE connection using EventSource
|
||||
|
|
@ -99,16 +96,7 @@ export default function BuildTrigger({
|
|||
// If the event is a log, log it
|
||||
setSuccessData({ title: parsedData.log });
|
||||
} else if (parsedData.input_keys !== undefined) {
|
||||
//@ts-ignore
|
||||
setTabsState((old: FlowsState) => {
|
||||
return {
|
||||
...old,
|
||||
[flowId]: {
|
||||
...old[flowId],
|
||||
formKeysData: parsedData,
|
||||
},
|
||||
};
|
||||
});
|
||||
setFlowState(parsedData);
|
||||
} else {
|
||||
// Otherwise, process the data
|
||||
const isValid = processStreamResult(parsedData);
|
||||
|
|
@ -154,14 +142,6 @@ export default function BuildTrigger({
|
|||
}
|
||||
}
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
setIsIconTouched(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setIsIconTouched(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Transition
|
||||
show={!open}
|
||||
|
|
@ -179,8 +159,6 @@ export default function BuildTrigger({
|
|||
onClick={() => {
|
||||
handleBuild(flow);
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<button>
|
||||
<div className="round-button-div">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { Transition } from "@headlessui/react";
|
||||
|
||||
import { useContext } from "react";
|
||||
import {
|
||||
CHAT_CANNOT_OPEN_DESCRIPTION,
|
||||
CHAT_CANNOT_OPEN_TITLE,
|
||||
FLOW_NOT_BUILT_DESCRIPTION,
|
||||
FLOW_NOT_BUILT_TITLE,
|
||||
} from "../../../constants/constants";
|
||||
import { alertContext } from "../../../contexts/alertContext";
|
||||
import useAlertStore from "../../../stores/alertStore";
|
||||
import { chatTriggerPropType } from "../../../types/components";
|
||||
import IconComponent from "../../genericIconComponent";
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ export default function ChatTrigger({
|
|||
isBuilt,
|
||||
canOpen,
|
||||
}: chatTriggerPropType): JSX.Element {
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
|
||||
function handleClick(): void {
|
||||
if (isBuilt) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useNodes } from "reactflow";
|
||||
import { ChatType } from "../../types/chat";
|
||||
import BuildTrigger from "./buildTrigger";
|
||||
import ChatTrigger from "./chatTrigger";
|
||||
|
||||
import * as _ from "lodash";
|
||||
import { FlowsContext } from "../../contexts/flowsContext";
|
||||
import { getBuildStatus } from "../../controllers/API";
|
||||
import FormModal from "../../modals/formModal";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import { NodeType } from "../../types/flow";
|
||||
|
||||
export default function Chat({ flow }: ChatType): JSX.Element {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [canOpen, setCanOpen] = useState(false);
|
||||
const { tabsState, isBuilt, setIsBuilt } = useContext(FlowsContext);
|
||||
|
||||
const isBuilt = useFlowStore((state) => state.isBuilt);
|
||||
const setIsBuilt = useFlowStore((state) => state.setIsBuilt);
|
||||
const flowState = useFlowStore((state) => state.flowState);
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
|
|
@ -50,27 +50,11 @@ export default function Chat({ flow }: ChatType): JSX.Element {
|
|||
const currentNodes = nodes.map((node: NodeType) =>
|
||||
_.cloneDeep(node.data.node?.template)
|
||||
);
|
||||
if (
|
||||
tabsState &&
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].isPending &&
|
||||
JSON.stringify(prevNodes) !== JSON.stringify(currentNodes)
|
||||
) {
|
||||
if (JSON.stringify(prevNodes) !== JSON.stringify(currentNodes)) {
|
||||
setIsBuilt(false);
|
||||
}
|
||||
if (
|
||||
tabsState &&
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
tabsState[flow.id].formKeysData.input_keys !== null
|
||||
) {
|
||||
setCanOpen(true);
|
||||
} else {
|
||||
setCanOpen(false);
|
||||
}
|
||||
|
||||
prevNodesRef.current = currentNodes;
|
||||
}, [tabsState, flow.id]);
|
||||
}, [flowState, flow.id]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -81,19 +65,11 @@ export default function Chat({ flow }: ChatType): JSX.Element {
|
|||
setIsBuilt={setIsBuilt}
|
||||
isBuilt={isBuilt}
|
||||
/>
|
||||
{isBuilt &&
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
canOpen && (
|
||||
<FormModal
|
||||
key={flow.id}
|
||||
flow={flow}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
)}
|
||||
{isBuilt && flowState && !!flowState?.input_keys && (
|
||||
<FormModal key={flow.id} flow={flow} open={open} setOpen={setOpen} />
|
||||
)}
|
||||
<ChatTrigger
|
||||
canOpen={canOpen}
|
||||
canOpen={!!flowState?.input_keys}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
isBuilt={isBuilt}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ export default function CodeAreaComponent({
|
|||
typeof value == "string" ? value : JSON.stringify(value)
|
||||
);
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
if (disabled && myValue !== "") {
|
||||
setMyValue("");
|
||||
onChange("");
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
}, [disabled]);
|
||||
|
||||
useEffect(() => {
|
||||
setMyValue(typeof value == "string" ? value : JSON.stringify(value));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { cloneDeep } from "lodash";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||
import AccordionComponent from "../../components/AccordionComponent";
|
||||
|
|
@ -28,8 +28,8 @@ import {
|
|||
TabsTrigger,
|
||||
} from "../../components/ui/tabs";
|
||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../constants/constants";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import { codeTabsPropsType } from "../../types/components";
|
||||
import {
|
||||
convertObjToArray,
|
||||
|
|
@ -53,8 +53,10 @@ export default function CodeTabsComponent({
|
|||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
||||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const dark = useDarkStore((state) => state.dark);
|
||||
|
||||
const setNodes = useFlowStore((state) => state.setNodes);
|
||||
|
||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -68,7 +70,7 @@ export default function CodeTabsComponent({
|
|||
unselectAllNodes({
|
||||
data,
|
||||
updateNodes: (nodes) => {
|
||||
reactFlowInstance?.setNodes(nodes);
|
||||
setNodes(nodes);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ export default function FloatComponent({
|
|||
const max = rangeSpec?.max ?? 2;
|
||||
// Clear component state
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
if (disabled && value !== "") {
|
||||
onChange("");
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
}, [disabled]);
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
|
|
@ -48,7 +48,7 @@ export default function FloatComponent({
|
|||
onChange(event.target.value);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
handleKeyDown(e, value, "0");
|
||||
handleKeyDown(e, value, "");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useContext, useState } from "react";
|
||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
|
@ -9,17 +8,18 @@ import {
|
|||
} from "../../../ui/dropdown-menu";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||
import FlowSettingsModal from "../../../../modals/flowSettingsModal";
|
||||
import { menuBarPropsType } from "../../../../types/components";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
||||
import IconComponent from "../../../genericIconComponent";
|
||||
import { Button } from "../../../ui/button";
|
||||
|
||||
export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
||||
const { addFlow } = useContext(FlowsContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const { undo, redo } = useContext(undoRedoContext);
|
||||
export const MenuBar = (): JSX.Element => {
|
||||
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const undo = useFlowsManagerStore((state) => state.undo);
|
||||
const redo = useFlowsManagerStore((state) => state.redo);
|
||||
const [openSettings, setOpenSettings] = useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
@ -34,9 +34,8 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
setErrorData(err as { title: string; list?: Array<string> });
|
||||
}
|
||||
}
|
||||
let current_flow = flows.find((flow) => flow.id === tabId);
|
||||
|
||||
return (
|
||||
return currentFlow ? (
|
||||
<div className="round-button-div">
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
@ -50,9 +49,7 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
<DropdownMenuTrigger asChild>
|
||||
<Button asChild variant="primary" size="sm">
|
||||
<div className="header-menu-bar-display">
|
||||
<div className="header-menu-flow-name">
|
||||
{current_flow!.name}
|
||||
</div>
|
||||
<div className="header-menu-flow-name">{currentFlow.name}</div>
|
||||
<IconComponent name="ChevronDown" className="h-4 w-4" />
|
||||
</div>
|
||||
</Button>
|
||||
|
|
@ -108,6 +105,8 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
></FlowSettingsModal>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue