Merge branch 'dev' into dropdownButton_component

This commit is contained in:
Lucas Oliveira 2023-08-31 10:42:19 -03:00
commit 66752b61ea
20 changed files with 418 additions and 304 deletions

View file

@ -1,3 +1,4 @@
from typing import Optional
from langflow.template.frontend_node.base import FrontendNode
from pydantic import BaseModel, validator
@ -20,7 +21,8 @@ class FrontendNodeRequest(FrontendNode):
class ValidatePromptRequest(BaseModel):
name: str
template: str
frontend_node: FrontendNodeRequest
#optional for tweak call
frontend_node: Optional[FrontendNodeRequest]
# Build ValidationResponse class for {"imports": {"errors": []}, "function": {"errors": []}}
@ -39,7 +41,8 @@ class CodeValidationResponse(BaseModel):
class PromptValidationResponse(BaseModel):
input_variables: list
frontend_node: FrontendNodeRequest
#object return for tweak call
frontend_node: FrontendNodeRequest | object
INVALID_CHARACTERS = {

View file

@ -18,6 +18,10 @@ from langflow.services.utils import get_session
from langflow.utils.logger import logger
from cachetools import LRUCache
from sqlmodel import Session
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from langflow.services.chat.manager import ChatManager
router = APIRouter(tags=["Chat"])
@ -33,21 +37,38 @@ async def chat(
):
"""Websocket endpoint for chat."""
try:
await websocket.accept()
user = await get_current_user(token, db)
if not user:
await websocket.close(
code=status.WS_1008_POLICY_VIOLATION, reason="Unauthorized"
)
if not user.is_active:
raise HTTPException(status_code=401, detail="Invalid token")
chat_manager = service_manager.get(ServiceType.CHAT_MANAGER)
await websocket.close(
code=status.WS_1008_POLICY_VIOLATION, reason="Unauthorized"
)
chat_manager: "ChatManager" = service_manager.get(ServiceType.CHAT_MANAGER)
if client_id in chat_manager.in_memory_cache:
await chat_manager.handle_websocket(client_id, websocket)
else:
# We accept the connection but close it immediately
# if the flow is not built yet
await websocket.accept()
message = "Please, build the flow before sending messages"
await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=message)
except WebSocketException as exc:
logger.error(f"Websocket error: {exc}")
await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc))
except Exception as exc:
logger.error(f"Error in chat websocket: {exc}")
if isinstance(exc, HTTPException):
exc = exc.detail
if "Could not validate credentials" in str(exc):
await websocket.close(
code=status.WS_1008_POLICY_VIOLATION, reason="Unauthorized"
)
else:
await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc))
@router.post("/build/init/{flow_id}", response_model=InitResponse, status_code=201)

View file

@ -31,7 +31,12 @@ def post_validate_code(code: Code):
def post_validate_prompt(prompt_request: ValidatePromptRequest):
try:
input_variables = validate_prompt(prompt_request.template)
# Check if frontend_node is None before proceeding to avoid attempting to update a non-existent node.
if prompt_request.frontend_node is None:
return PromptValidationResponse(
input_variables=input_variables,
frontend_node={},
)
old_custom_fields = get_old_custom_fields(prompt_request)
add_new_variables_to_template(input_variables, prompt_request)

View file

@ -88,6 +88,11 @@ async def get_current_user(
)
user_id: UUID = payload.get("sub") # type: ignore
token_type: str = payload.get("type") # type: ignore
if expires := payload.get("exp", None):
expires_datetime = datetime.fromtimestamp(expires, timezone.utc)
# TypeError: can't compare offset-naive and offset-aware datetimes
if datetime.now(timezone.utc) > expires_datetime:
raise credentials_exception
if user_id is None or token_type:
raise credentials_exception

View file

@ -92,7 +92,6 @@ class ChatManager(Service):
)
async def connect(self, client_id: str, websocket: WebSocket):
await websocket.accept()
self.active_connections[client_id] = websocket
def disconnect(self, client_id: str):

View file

@ -1,13 +1,21 @@
from pathlib import Path
from typing import Optional
import secrets
from langflow.services.settings.utils import read_secret_from_file, write_secret_to_file
from pydantic import BaseSettings
from pydantic import BaseSettings, Field, validator
from passlib.context import CryptContext
from langflow.utils.logger import logger
class AuthSettings(BaseSettings):
# Login settings
SECRET_KEY: str = secrets.token_hex(32)
CONFIG_DIR: str
SECRET_KEY: Optional[str] = Field(
None,
description="Secret key for JWT. If not provided, a random one will be generated.",
env="LANGFLOW_SECRET_KEY",
)
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60
REFRESH_TOKEN_EXPIRE_MINUTES: int = 70
@ -31,3 +39,33 @@ class AuthSettings(BaseSettings):
validate_assignment = True
extra = "ignore"
env_prefix = "LANGFLOW_"
@validator("SECRET_KEY", pre=True)
def get_secret_key(cls, value, values):
config_dir = values.get("CONFIG_DIR")
if not config_dir:
logger.debug("No CONFIG_DIR provided, not saving secret key")
return value or secrets.token_urlsafe(32)
secret_key_path = Path(config_dir) / "secret_key"
if value:
logger.debug("Secret key provided")
write_secret_to_file(secret_key_path, value)
else:
logger.debug("No secret key provided, generating a random one")
if secret_key_path.exists():
value = read_secret_from_file(secret_key_path)
logger.debug("Loaded secret key")
if not value:
value = secrets.token_urlsafe(32)
write_secret_to_file(secret_key_path, value)
logger.debug("Saved secret key")
else:
value = secrets.token_urlsafe(32)
write_secret_to_file(secret_key_path, value)
logger.debug("Saved secret key")
return value

View file

@ -35,5 +35,5 @@ class SettingsManager(Service):
)
settings = Settings(**settings_dict)
auth_settings = AuthSettings()
auth_settings = AuthSettings(CONFIG_DIR=settings.CONFIG_DIR)
return cls(settings, auth_settings)

View file

@ -0,0 +1,47 @@
import os
from pathlib import Path
import platform
from langflow.utils.logger import logger
def set_secure_permissions(file_path):
if platform.system() in ["Linux", "Darwin"]: # Unix/Linux/Mac
os.chmod(file_path, 0o600)
elif platform.system() == "Windows":
import win32api
import win32con
import win32security
user, domain, _ = win32security.LookupAccountName("", win32api.GetUserName())
sd = win32security.GetFileSecurity(
file_path, win32security.DACL_SECURITY_INFORMATION
)
dacl = win32security.ACL()
# Set the new DACL for the file: read and write access for the owner, no access for everyone else
dacl.AddAccessAllowedAce(
win32security.ACL_REVISION,
win32con.GENERIC_READ | win32con.GENERIC_WRITE,
user,
)
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(
file_path, win32security.DACL_SECURITY_INFORMATION, sd
)
else:
print("Unsupported OS")
def write_secret_to_file(path: Path, value: str) -> None:
with path.open("wb") as f:
f.write(value.encode("utf-8"))
try:
set_secure_permissions(path)
except Exception:
logger.error("Failed to set secure permissions on secret key")
def read_secret_from_file(path: Path) -> str:
with path.open("rb") as f:
return f.read()

View file

@ -8,11 +8,11 @@
"name": "langflow",
"version": "0.1.2",
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@headlessui/react": "^1.7.10",
"@heroicons/react": "^2.0.15",
"@mui/material": "^5.11.9",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@headlessui/react": "^1.7.17",
"@heroicons/react": "^2.0.18",
"@mui/material": "^5.14.7",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
@ -29,20 +29,20 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.18.0",
"@tailwindcss/forms": "^0.5.3",
"@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6",
"@tailwindcss/line-clamp": "^0.4.4",
"@types/axios": "^0.14.0",
"accordion": "^3.0.2",
"ace-builds": "^1.16.0",
"ace-builds": "^1.24.1",
"add": "^2.0.6",
"ansi-to-html": "^0.7.2",
"axios": "^1.3.2",
"axios": "^1.5.0",
"base64-js": "^1.5.1",
"class-variance-authority": "^0.6.0",
"class-variance-authority": "^0.6.1",
"clsx": "^1.2.1",
"dompurify": "^3.0.4",
"esbuild": "^0.17.18",
"dompurify": "^3.0.5",
"esbuild": "^0.17.19",
"lodash": "^4.17.21",
"lucide-react": "^0.233.0",
"moment": "^2.29.4",
@ -50,51 +50,51 @@
"react-ace": "^10.1.0",
"react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.2",
"react-icons": "^4.8.0",
"react-error-boundary": "^4.0.11",
"react-icons": "^4.10.1",
"react-laag": "^2.0.5",
"react-markdown": "^8.0.7",
"react-router-dom": "^6.8.1",
"react-router-dom": "^6.15.0",
"react-syntax-highlighter": "^15.5.0",
"react-tabs": "^6.0.0",
"react-tooltip": "^5.13.1",
"react-tabs": "^6.0.2",
"react-tooltip": "^5.21.1",
"reactflow": "^11.8.3",
"rehype-mathjax": "^4.0.2",
"rehype-mathjax": "^4.0.3",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"shadcn-ui": "^0.2.2",
"shadcn-ui": "^0.2.3",
"short-unique-id": "^4.4.4",
"switch": "^0.0.0",
"table": "^6.8.1",
"tailwind-merge": "^1.13.0",
"tailwindcss-animate": "^1.0.5",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"uuid": "^9.0.0",
"vite-plugin-svgr": "^3.2.0",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.62",
"@swc/core": "^1.3.80",
"@tailwindcss/typography": "^0.5.9",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.194",
"@types/node": "^16.18.12",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.1",
"@vitejs/plugin-react-swc": "^3.0.0",
"autoprefixer": "^10.4.14",
"daisyui": "^3.1.1",
"postcss": "^8.4.23",
"@types/lodash": "^4.14.197",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.15",
"daisyui": "^3.6.3",
"postcss": "^8.4.29",
"prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.2",
"prettier-plugin-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "^0.3.0",
"tailwindcss": "^3.3.2",
"typescript": "^5.0.2",
"vite": "^4.3.9"
"tailwindcss": "^3.3.3",
"typescript": "^5.2.2",
"vite": "^4.4.9"
}
},
"node_modules/@adobe/css-tools": {
@ -5514,9 +5514,9 @@
}
},
"node_modules/fraction.js": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.0.tgz",
"integrity": "sha512-btalnXjFelOv2cy86KzHWhUuMb622/AD8ce/MCH9C36xe7QRXjJZA+19fP+G5LT0fdRcbOHErMI3SPM11ZaVDg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.1.tgz",
"integrity": "sha512-nx0cki48JBA6ThPeUpeKCNpdhEl/9bRS+dAEYnRUod+Z1jhFfC3K/mBLorZZntqHM+GTH3/dkkpfoT3QITYe7g==",
"dev": true,
"engines": {
"node": "*"
@ -14721,9 +14721,9 @@
}
},
"fraction.js": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.0.tgz",
"integrity": "sha512-btalnXjFelOv2cy86KzHWhUuMb622/AD8ce/MCH9C36xe7QRXjJZA+19fP+G5LT0fdRcbOHErMI3SPM11ZaVDg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.1.tgz",
"integrity": "sha512-nx0cki48JBA6ThPeUpeKCNpdhEl/9bRS+dAEYnRUod+Z1jhFfC3K/mBLorZZntqHM+GTH3/dkkpfoT3QITYe7g==",
"dev": true
},
"fs-extra": {

View file

@ -3,11 +3,11 @@
"version": "0.1.2",
"private": true,
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@headlessui/react": "^1.7.10",
"@heroicons/react": "^2.0.15",
"@mui/material": "^5.11.9",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@headlessui/react": "^1.7.17",
"@heroicons/react": "^2.0.18",
"@mui/material": "^5.14.7",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
@ -24,20 +24,20 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.18.0",
"@tailwindcss/forms": "^0.5.3",
"@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6",
"@tailwindcss/line-clamp": "^0.4.4",
"@types/axios": "^0.14.0",
"accordion": "^3.0.2",
"ace-builds": "^1.16.0",
"ace-builds": "^1.24.1",
"add": "^2.0.6",
"ansi-to-html": "^0.7.2",
"axios": "^1.3.2",
"axios": "^1.5.0",
"base64-js": "^1.5.1",
"class-variance-authority": "^0.6.0",
"class-variance-authority": "^0.6.1",
"clsx": "^1.2.1",
"dompurify": "^3.0.4",
"esbuild": "^0.17.18",
"dompurify": "^3.0.5",
"esbuild": "^0.17.19",
"lodash": "^4.17.21",
"lucide-react": "^0.233.0",
"moment": "^2.29.4",
@ -45,24 +45,24 @@
"react-ace": "^10.1.0",
"react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.2",
"react-icons": "^4.8.0",
"react-error-boundary": "^4.0.11",
"react-icons": "^4.10.1",
"react-laag": "^2.0.5",
"react-markdown": "^8.0.7",
"react-router-dom": "^6.8.1",
"react-router-dom": "^6.15.0",
"react-syntax-highlighter": "^15.5.0",
"react-tabs": "^6.0.0",
"react-tooltip": "^5.13.1",
"react-tabs": "^6.0.2",
"react-tooltip": "^5.21.1",
"reactflow": "^11.8.3",
"rehype-mathjax": "^4.0.2",
"rehype-mathjax": "^4.0.3",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"shadcn-ui": "^0.2.2",
"shadcn-ui": "^0.2.3",
"short-unique-id": "^4.4.4",
"switch": "^0.0.0",
"table": "^6.8.1",
"tailwind-merge": "^1.13.0",
"tailwindcss-animate": "^1.0.5",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"uuid": "^9.0.0",
"vite-plugin-svgr": "^3.2.0",
"web-vitals": "^2.1.4"
@ -96,26 +96,26 @@
"proxy": "http://127.0.0.1:7860",
"devDependencies": {
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.62",
"@swc/core": "^1.3.80",
"@tailwindcss/typography": "^0.5.9",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.194",
"@types/node": "^16.18.12",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.1",
"@vitejs/plugin-react-swc": "^3.0.0",
"autoprefixer": "^10.4.14",
"daisyui": "^3.1.1",
"postcss": "^8.4.23",
"@types/lodash": "^4.14.197",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.15",
"daisyui": "^3.6.3",
"postcss": "^8.4.29",
"prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.2",
"prettier-plugin-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "^0.3.0",
"tailwindcss": "^3.3.2",
"typescript": "^5.0.2",
"vite": "^4.3.9"
"tailwindcss": "^3.3.3",
"typescript": "^5.2.2",
"vite": "^4.4.9"
}
}

View file

@ -49,7 +49,6 @@ export default function CodeTabsComponent({
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
const { dark } = useContext(darkContext);
const { reactFlowInstance } = useContext(typesContext);
const { isTweakPage, setIsTweakPage } = useContext(alertContext);
useEffect(() => {
if (flow && flow["data"]!["nodes"]) {
@ -58,16 +57,14 @@ export default function CodeTabsComponent({
}, [flow]);
useEffect(() => {
unselectAllNodes({
data,
updateNodes: (nodes) => {
reactFlowInstance?.setNodes(nodes);
},
});
return () => {
if (isTweakPage) setIsTweakPage(false);
};
if(tweaks){
unselectAllNodes({
data,
updateNodes: (nodes) => {
reactFlowInstance?.setNodes(nodes);
},
});
}
}, []);
const copyToClipboard = () => {

View file

@ -25,9 +25,7 @@ const initialValue: alertContextType = {
notificationList: [],
pushNotificationList: () => {},
clearNotificationList: () => {},
removeFromNotificationList: () => {},
isTweakPage: false,
setIsTweakPage: () => {},
removeFromNotificationList: () => {}
};
export const alertContext = createContext<alertContextType>(initialValue);
@ -123,8 +121,6 @@ export function AlertProvider({ children }: { children: ReactNode }) {
return (
<alertContext.Provider
value={{
isTweakPage,
setIsTweakPage,
removeFromNotificationList,
clearNotificationList,
notificationList,

View file

@ -33,7 +33,7 @@ function ApiInterceptor() {
}
const res = await renewAccessToken(refreshToken);
login(res.data.access_token, res.data.refresh_token);
login(res?.data?.access_token, res?.data?.refresh_token);
try {
if (error?.config?.headers) {
delete error.config.headers["Authorization"];

View file

@ -312,7 +312,7 @@ export async function getHealth() {
*/
export async function getBuildStatus(
flowId: string
): Promise<BuildStatusTypeAPI> {
): Promise<AxiosResponse<BuildStatusTypeAPI>> {
return await api.get(`${BASE_URL_API}build/${flowId}/status`);
}

View file

@ -8,7 +8,7 @@ import { classNames } from "../../utils/utils";
import ChatInput from "./chatInput";
import ChatMessage from "./chatMessage";
import _ from "lodash";
import _, { set } from "lodash";
import AccordionComponent from "../../components/AccordionComponent";
import IconComponent from "../../components/genericIconComponent";
import ToggleShadComponent from "../../components/toggleShadComponent";
@ -27,6 +27,7 @@ import { AuthContext } from "../../contexts/authContext";
import { TabsContext } from "../../contexts/tabsContext";
import { TabsState } from "../../types/tabs";
import { validateNodes } from "../../utils/reactflowUtils";
import { getBuildStatus } from "../../controllers/API";
export default function FormModal({
flow,
@ -155,9 +156,21 @@ export default function FormModal({
function handleOnClose(event: CloseEvent): void {
if (isOpen.current) {
getBuildStatus(flow.id).then((response) => {
if (response.data.built) {
connectWS();
}
else {
setErrorData({
title: "Please build the flow again before using the chat."
})
}
}).catch((error) => {
setErrorData({title:error.data?.detail?error.data.detail:error.message})
});
setErrorData({ title: event.reason });
setTimeout(() => {
connectWS();
setLockChat(false);
}, 1000);
}
@ -173,9 +186,8 @@ export default function FormModal({
const host = isDevelopment ? "localhost:7860" : window.location.host;
const chatEndpoint = `/api/v1/chat/${chatId}`;
return `${
isDevelopment ? "ws" : webSocketProtocol
}://${host}${chatEndpoint}?token=${accessToken}`;
return `${isDevelopment ? "ws" : webSocketProtocol
}://${host}${chatEndpoint}?token=${encodeURIComponent(accessToken!)}`;
}
function handleWsMessage(data: any) {
@ -197,20 +209,20 @@ export default function FormModal({
newChatHistory.push(
chatItem.files
? {
isSend: !chatItem.is_bot,
message: chatItem.message,
template: chatItem.template,
thought: chatItem.intermediate_steps,
files: chatItem.files,
chatKey: chatItem.chatKey,
}
isSend: !chatItem.is_bot,
message: chatItem.message,
template: chatItem.template,
thought: chatItem.intermediate_steps,
files: chatItem.files,
chatKey: chatItem.chatKey,
}
: {
isSend: !chatItem.is_bot,
message: chatItem.message,
template: chatItem.template,
thought: chatItem.intermediate_steps,
chatKey: chatItem.chatKey,
}
isSend: !chatItem.is_bot,
message: chatItem.message,
template: chatItem.template,
thought: chatItem.intermediate_steps,
chatKey: chatItem.chatKey,
}
);
}
}
@ -260,7 +272,6 @@ export default function FormModal({
};
newWs.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received data:", data);
handleWsMessage(data);
//get chat history
};
@ -268,7 +279,6 @@ export default function FormModal({
handleOnClose(event);
};
newWs.onerror = (ev) => {
console.log(ev, "error");
if (flow.id === "") {
connectWS();
} else {
@ -294,7 +304,6 @@ export default function FormModal({
useEffect(() => {
connectWS();
return () => {
console.log("unmount");
console.log(ws);
if (ws.current) {
ws.current.close();
@ -433,73 +442,73 @@ export default function FormModal({
{tabsState[id.current]?.formKeysData?.input_keys
? Object.keys(
tabsState[id.current].formKeysData.input_keys!
).map((key, index) => (
<div className="file-component-accordion-div" key={index}>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{key}
</Badge>
tabsState[id.current].formKeysData.input_keys!
).map((key, index) => (
<div className="file-component-accordion-div" key={index}>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{key}
</Badge>
<div
className="-mb-1"
onClick={(event) => {
event.stopPropagation();
}}
>
<ToggleShadComponent
enabled={chatKey === key}
setEnabled={(value) =>
handleOnCheckedChange(value, key)
}
size="small"
disabled={tabsState[
id.current
].formKeysData.handle_keys!.some(
(t) => t === key
)}
/>
</div>
<div
className="-mb-1"
onClick={(event) => {
event.stopPropagation();
}}
>
<ToggleShadComponent
enabled={chatKey === key}
setEnabled={(value) =>
handleOnCheckedChange(value, key)
}
size="small"
disabled={tabsState[
id.current
].formKeysData.handle_keys!.some(
(t) => t === key
)}
/>
</div>
}
key={index}
keyValue={key}
>
<div className="file-component-tab-column">
{tabsState[id.current].formKeysData.handle_keys!.some(
(t) => t === key
) && (
</div>
}
key={index}
keyValue={key}
>
<div className="file-component-tab-column">
{tabsState[id.current].formKeysData.handle_keys!.some(
(t) => t === key
) && (
<div className="font-normal text-muted-foreground ">
Source: Component
</div>
)}
<Textarea
className="custom-scroll"
value={
tabsState[id.current].formKeysData.input_keys![
key
]
}
onChange={(e) => {
//@ts-ignore
setTabsState((old: TabsState) => {
let newTabsState = _.cloneDeep(old);
newTabsState[
id.current
].formKeysData.input_keys![key] =
e.target.value;
return newTabsState;
});
}}
disabled={chatKey === key}
placeholder="Enter text..."
></Textarea>
</div>
</AccordionComponent>
</div>
))
<Textarea
className="custom-scroll"
value={
tabsState[id.current].formKeysData.input_keys![
key
]
}
onChange={(e) => {
//@ts-ignore
setTabsState((old: TabsState) => {
let newTabsState = _.cloneDeep(old);
newTabsState[
id.current
].formKeysData.input_keys![key] =
e.target.value;
return newTabsState;
});
}}
disabled={chatKey === key}
placeholder="Enter text..."
></Textarea>
</div>
</AccordionComponent>
</div>
))
: null}
{tabsState[id.current].formKeysData.memory_keys!.map(
(key, index) => (
@ -513,7 +522,7 @@ export default function FormModal({
<div className="-mb-1">
<ToggleShadComponent
enabled={chatKey === key}
setEnabled={() => {}}
setEnabled={() => { }}
size="small"
disabled={true}
/>

View file

@ -121,6 +121,7 @@ export default function GenericModal({
}
function validatePrompt(closeModal: boolean): void {
//nodeClass is always null on tweaks
postValidatePrompt(field_name, inputValue, nodeClass!)
.then((apiReturn) => {
if (apiReturn.data) {
@ -135,7 +136,7 @@ export default function GenericModal({
setSuccessData({
title: "Prompt is ready",
});
setNodeClass!(apiReturn.data?.frontend_node);
if(JSON.stringify(apiReturn.data?.frontend_node)!==JSON.stringify({})) setNodeClass!(apiReturn.data?.frontend_node);
setModalOpen(closeModal);
setValue(inputValue);
}

View file

@ -21,7 +21,7 @@ export default function ExtraSidebar(): JSX.Element {
const { data, templates } = useContext(typesContext);
const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt } =
useContext(TabsContext);
const { setSuccessData, setErrorData, setIsTweakPage } =
const { setSuccessData, setErrorData } =
useContext(alertContext);
const [dataFilter, setFilterData] = useState(data);
const [search, setSearch] = useState("");
@ -103,7 +103,6 @@ export default function ExtraSidebar(): JSX.Element {
<ApiModal flow={flow} disable={!isBuilt}>
<div
className={classNames("extra-side-bar-buttons")}
onClick={() => setIsTweakPage(true)}
>
<IconComponent
name="Code2"

View file

@ -41,8 +41,6 @@ export type alertContextType = {
removeFromNotificationList: (index: string) => void;
loading: boolean;
setLoading: (newState: boolean) => void;
isTweakPage: boolean;
setIsTweakPage: (newState: boolean) => void;
};
export type darkContextType = {