Squashed commit of the following:

commit 5c3f3dbb70
Author: italojohnny <italojohnnydosanjos@gmail.com>
Date:   Wed Jun 5 17:57:08 2024 -0300

    fix libs

commit 2c7d7616fa
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Wed Jun 5 17:45:17 2024 -0300

    fix selection bug on Messages Table

commit 183f0bcca5
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Wed Jun 5 17:28:01 2024 -0300

    update route

commit 79f998333f
Merge: be919f1bc bcdc329d1
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Wed Jun 5 16:51:59 2024 -0300

    Merge remote-tracking branch 'origin/dev' into SessionManagment

commit be919f1bca
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Tue Jun 4 17:06:16 2024 -0300

    Refactor: Remove commented code for chat history tab in IOModal

commit 91e3bd9151
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Tue Jun 4 16:33:05 2024 -0300

    Refactor: Remove select from delete session button

commit 83b837966d
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Tue Jun 4 15:53:51 2024 -0300

    Refactor: Make Reset Column button reset columns order

commit 254a2c423c
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Tue Jun 4 14:38:40 2024 -0300

    Refactor: Add ResetColumns component to improve table functionality

commit 5275126e64
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Tue Jun 4 14:06:38 2024 -0300

    chore: Update description text in SettingsPage

commit fb27528a00
Merge: 002475331 3369b54b8
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Mon Jun 3 22:17:15 2024 -0300

    Merge branch 'SessionManagment' of personal:langflow-ai/langflow into SessionManagment

commit 3369b54b83
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon Jun 3 20:03:40 2024 -0300

    Refactor: remove page size directly in css file

commit c8fad13a3c
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon Jun 3 19:42:06 2024 -0300

    Refactor: Remove “Page size” from table pagination

commit 49882e4201
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon Jun 3 19:34:43 2024 -0300

    Remove unnused imports

commit cd36ff8ad7
Merge: cdf9d77b4 adeaf4db9
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon Jun 3 19:28:44 2024 -0300

    Merge SessionManagement into SessionManagement

commit cdf9d77b45
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon Jun 3 19:25:47 2024 -0300

    Feat: Make the table last column non-resizable and add a restore columns button

commit 002475331e
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Mon Jun 3 18:27:35 2024 -0300

    update editable fields

commit adeaf4db91
Merge: d670ec8d6 818696a66
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 18:17:19 2024 -0300

    Merge branch 'SessionManagment' of https://github.com/langflow-ai/langflow into SessionManagment

commit d670ec8d64
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 18:17:15 2024 -0300

    🐛 (service.py): add missing 'id' column in SQL query to fix data retrieval issue
    💡 (service.py): add print statement for debugging SQL query
    ♻️ (index.tsx): reorder imports for better readability and maintainability

    ♻️ (flowStore.ts): remove trailing commas to improve code consistency and readability

    💡 (index.ts, storeUtils.ts): format type definitions for better readability

commit 818696a661
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Mon Jun 3 17:37:14 2024 -0300

    refactor: Add getSessions function to fetch available sessions in IOModal

commit 895df8c050
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 17:05:50 2024 -0300

    ♻️ (monitor.py, service.py): remove trailing whitespace to improve code cleanliness

commit 0e56617e26
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 17:05:39 2024 -0300

    ♻️ (monitor.py): refactor update_message to return MessageModelResponse
    ♻️ (service.py): update SQL query to use index instead of id
    ♻️ (api.tsx): refactor duplicate request check logic
    ✨ (check-duplicate-requests.ts): add helper to check and store duplicate requests
    🐛 (messagesStore.ts): fix message update logic to use index instead of id

commit 41c2d7feb5
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Mon Jun 3 14:48:05 2024 -0300

    start history in playgroundModal

commit 93568b4c0d
Merge: 21a8545dd f3922dfff
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 10:31:46 2024 -0300

    ✨ (tableComponent): add editable prop to TableComponent for column editing
    ✨ (API): add updateMessageApi function to update messages via API
    ✨ (chatView): add select dropdown for clearing builds and sessions
    ♻️ (use-messages-table): refactor to use messages store for setting messages
    ♻️ (use-remove-messages): remove setRows and use messages store for deletion
    ✨ (use-updateMessage): add hook for updating messages with API integration
    📝 (headerMessages): update header message text in messages page

    ✨ (messagesPage): add cell edit request handling for message updates
    ♻️ (messagesPage): refactor state management and hooks usage
    ✨ (types): add new types for chat and message handling

commit 21a8545ddb
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Mon Jun 3 10:29:58 2024 -0300

    ♻️ (monitor.py): change POST to DELETE for delete_messages endpoint
    ♻️ (schemas.py): remove unused MessageIds schema
    ♻️ (api.tsx): add missing commas in ApiInterceptor function
    🐛 (api.tsx): fix duplicate request check to include method "get"
    ♻️ (index.ts): change deleteMessagesFn to use DELETE method instead of POST
    ♻️ (use-remove-messages.tsx): clean up comments and improve error handling

commit f3922dfff6
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Sun Jun 2 19:38:15 2024 -0300

    refactor: Move editable attribute to TableComponent
    add update function, need to fix backend

commit 1a65af7602
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Sun Jun 2 18:07:45 2024 -0300

    move editable attribute to table Component

commit 729150a5a4
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Fri May 31 22:40:53 2024 -0300

    refactor(headerMessages): update text content in HeaderMessagesComponent

commit 1d06969364
Merge: 57c38acac 70f4fd077
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Fri May 31 17:47:08 2024 -0300

    Merge remote-tracking branch 'origin/ic/flow_eraser_dropdown' into SessionManagment

commit 57c38acace
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Fri May 31 13:43:41 2024 -0300

    💡 (schemas.py): add newline at end of file to follow PEP 8 guidelines

commit 602ebf7b15
Author: cristhianzl <cristhian.lousa@gmail.com>
Date:   Fri May 31 13:43:28 2024 -0300

    ✨ (monitor.py): add MessageIds schema for structured message deletion
    ♻️ (monitor.py): change delete_messages endpoint to POST for better semantics
    ♻️ (monitor.py): update delete_messages to use MessageIds schema
    ✨ (schemas.py): add MessageIds schema for structured message deletion
    🐛 (service.py): fix SQL query in delete_messages to use correct column name
    ✨ (index.tsx): add toTitleCase utility to format column headers
    ✨ (API/index.ts): add deleteMessagesFn to handle message deletion via API
    ✨ (headerMessages): add HeaderMessagesComponent for message management UI
    ✨ (use-messages-table): add useMessagesTable hook to fetch and manage messages
    ✨ (use-remove-messages): add useRemoveMessages hook to handle message deletion

    ♻️ (messagesPage): refactor messages page to use new messages store
    ✨ (messagesStore): create zustand store for managing messages state
    ✨ (types): add types for messages and zustand messages store

commit f79289f966
Author: ogabrielluiz <gabriel@langflow.org>
Date:   Fri May 31 09:38:05 2024 -0300

    feat: Add API endpoints for managing messages

    This commit adds new API endpoints for managing messages. It includes the ability to delete messages by their IDs, update a specific message, and delete all messages associated with a session. These changes are implemented in the `monitor.py`, `schema.py`, and `service.py` files.

commit a99d0c7eb0
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Wed May 29 17:48:12 2024 -0300

    refactor(tableComponent): update column definitions to include checkbox selection logic for first column

    feat(API): add support for excluding specific columns in getMessagesTable function

    fix(flowLogsModal): pass excludedFields parameter to getMessagesTable function

    refactor(GlobalVariablesPage): remove unnecessary checkbox selection properties from column definitions

    fix(messagesPage): pass excludedFields parameter to getMessagesTable function

    refactor(utils): add support for excluding specific columns in extractColumnsFromRows function

commit 022ef7c028
Author: anovazzi1 <otavio2204@gmail.com>
Date:   Wed May 29 17:15:21 2024 -0300

    feat: Add Messages page to SettingsPage

    Refactor the SettingsPage component to include a new "Messages" page. This page will be accessible through the "/settings/messages" route and will display messages related to user settings. The necessary changes have been made to the index.tsx file of the SettingsPage component and the routes.tsx file.

commit 70f4fd0770
Author: igorrCarvalho <igorsilvabhz6@gmail.com>
Date:   Mon May 27 21:36:00 2024 -0300

    Feat: Create the first version of the eraser tool
This commit is contained in:
anovazzi1 2024-06-05 18:53:29 -03:00
commit af80b4c4e1
69 changed files with 1433 additions and 758 deletions

View file

@ -86,11 +86,12 @@ from langflow.load import run_flow_from_json
results = run_flow_from_json("path/to/flow.json", input_value="Hello, World!") results = run_flow_from_json("path/to/flow.json", input_value="Hello, World!")
``` ```
# 部署 # 部署
## 在Google Cloud Platform上部署Langflow ## 在Google Cloud Platform上部署Langflow
请按照我们的分步指南使用 Google Cloud Shell 在 Google Cloud Platform (GCP) 上部署 Langflow。该指南在 [**Langflow in Google Cloud Platform**](GCP_DEPLOYMENT.md) 文档中提供。 请按照我们的分步指南使用 Google Cloud Shell 在 Google Cloud Platform (GCP) 上部署 Langflow。该指南在 [**Langflow in Google Cloud Platform**](GCP_DEPLOYMENT.md) 文档中提供。
或者,点击下面的 "Open in Cloud Shell" 按钮,启动 Google Cloud Shell,克隆 Langflow 仓库,并开始一个互动教程,该教程将指导您设置必要的资源并在 GCP 项目中部署 Langflow。 或者,点击下面的 "Open in Cloud Shell" 按钮,启动 Google Cloud Shell,克隆 Langflow 仓库,并开始一个互动教程,该教程将指导您设置必要的资源并在 GCP 项目中部署 Langflow。
@ -168,4 +169,4 @@ langflow run [OPTIONS]
# 📄 许可证 # 📄 许可证
Langflow 以 MIT 许可证发布。有关详细信息,请参阅 [LICENSE](LICENSE) 文件。 Langflow 以 MIT 许可证发布。有关详细信息,请参阅 [LICENSE](LICENSE) 文件。

View file

@ -17,7 +17,6 @@ Global Variables are a useful feature of Langflow, allowing you to define reusab
- All Credential Global Variables are encrypted and accessible only by you. - All Credential Global Variables are encrypted and accessible only by you.
- Set _`LANGFLOW_STORE_ENVIRONMENT_VARIABLES`_ to _`true`_ in your `.env` file to add all variables in _`LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT`_ to your user's Global Variables. - Set _`LANGFLOW_STORE_ENVIRONMENT_VARIABLES`_ to _`true`_ in your `.env` file to add all variables in _`LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT`_ to your user's Global Variables.
## Creating and Adding a Global Variable ## Creating and Adding a Global Variable
To create and add a global variable, click the 🌐 button in a Text field, and then click **+ Add New Variable**. To create and add a global variable, click the 🌐 button in a Text field, and then click **+ Add New Variable**.
@ -25,18 +24,20 @@ To create and add a global variable, click the 🌐 button in a Text field, and
Text fields are where you write text without opening a Text area, and are identified with the 🌐 icon. Text fields are where you write text without opening a Text area, and are identified with the 🌐 icon.
For example, to create an environment variable for the **OpenAI** component: For example, to create an environment variable for the **OpenAI** component:
1. In the **OpenAI API Key** text field, click the 🌐 button, then **Add New Variable**.
2. Enter `openai_api_key` in the **Variable Name** field. 1. In the **OpenAI API Key** text field, click the 🌐 button, then **Add New Variable**.
3. Paste your OpenAI API Key (`sk-...`) in the **Value** field. 2. Enter `openai_api_key` in the **Variable Name** field.
4. Select **Credential** for the **Type**. 3. Paste your OpenAI API Key (`sk-...`) in the **Value** field.
5. Choose **OpenAI API Key** in the **Apply to Fields** field to apply this variable to all fields named **OpenAI API Key**. 4. Select **Credential** for the **Type**.
6. Click **Save Variable**. 5. Choose **OpenAI API Key** in the **Apply to Fields** field to apply this variable to all fields named **OpenAI API Key**.
6. Click **Save Variable**.
You now have a `openai_api_key` global environment variable for your Langflow project. You now have a `openai_api_key` global environment variable for your Langflow project.
Subsequently, clicking the 🌐 button in a Text field will display the new variable in the dropdown. Subsequently, clicking the 🌐 button in a Text field will display the new variable in the dropdown.
<Admonition type="tip"> <Admonition type="tip">
You can also create global variables in **Settings** > **Variables and Secrets**. You can also create global variables in **Settings** > **Variables and
Secrets**.
</Admonition> </Admonition>
<ZoomableImage <ZoomableImage
@ -65,7 +66,8 @@ Setting `LANGFLOW_STORE_ENVIRONMENT_VARIABLES` to `true` in your `.env` file (de
These variables are accessible like any other Global Variable. These variables are accessible like any other Global Variable.
<Admonition type="tip"> <Admonition type="tip">
To prevent this behavior, set `LANGFLOW_STORE_ENVIRONMENT_VARIABLES` to `false` in your `.env` file. To prevent this behavior, set `LANGFLOW_STORE_ENVIRONMENT_VARIABLES` to
`false` in your `.env` file.
</Admonition> </Admonition>
You can specify variables to get from the environment by listing them in `LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT`. You can specify variables to get from the environment by listing them in `LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT`.

View file

@ -1,4 +1,4 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
import ZoomableImage from "/src/theme/ZoomableImage.js"; import ZoomableImage from "/src/theme/ZoomableImage.js";
# Inputs and Outputs # Inputs and Outputs
@ -29,9 +29,8 @@ This component collects user input from the chat.
<Admonition type="note" title="Note"> <Admonition type="note" title="Note">
<p> <p>
If `As Record` is `true` and the `Message` is a `Record`, the data If `As Record` is `true` and the `Message` is a `Record`, the data of the
of the `Record` will be updated with the `Sender`, `Sender Name`, and `Record` will be updated with the `Sender`, `Sender Name`, and `Session ID`.
`Session ID`.
</p> </p>
</Admonition> </Admonition>
@ -112,9 +111,10 @@ This component sends a message to the chat.
- **Message:** Specifies the text of the message. - **Message:** Specifies the text of the message.
<Admonition type="note" title="Note"> <Admonition type="note" title="Note">
<p> <p>
If `As Record` is `true` and the `Message` is a `Record`, the data in the `Record` is updated with the `Sender`, `Sender Name`, and `Session ID`. If `As Record` is `true` and the `Message` is a `Record`, the data in the
</p> `Record` is updated with the `Sender`, `Sender Name`, and `Session ID`.
</p>
</Admonition> </Admonition>
### Text Output ### Text Output
@ -125,7 +125,6 @@ This component displays text data to the user. It is useful when you want to sho
- **Value:** Specifies the text data to be displayed. Defaults to an empty string. - **Value:** Specifies the text data to be displayed. Defaults to an empty string.
The `TextOutput` component provides a simple way to display text data. It allows textual data to be visible in the chat window during your interaction flow. The `TextOutput` component provides a simple way to display text data. It allows textual data to be visible in the chat window during your interaction flow.
## Prompts ## Prompts
@ -155,7 +154,8 @@ The `PromptTemplate` component enables users to create prompts and define variab
<Admonition type="info"> <Admonition type="info">
After defining a variable in the prompt template, it acts as its own component After defining a variable in the prompt template, it acts as its own component
input. See [Prompt Customization](../administration/prompt-customization) for more details. input. See [Prompt Customization](../administration/prompt-customization) for
more details.
</Admonition> </Admonition>
- **template:** The template used to format an individual request. - **template:** The template used to format an individual request.

View file

@ -2,7 +2,7 @@
In Langflow 1.0, we added two main input and output types: `Text` and `Record`. In Langflow 1.0, we added two main input and output types: `Text` and `Record`.
`Text` is a simple string input and output type, while ``Record`` is a structure very similar to a dictionary in Python. It is a key-value pair data structure. `Text` is a simple string input and output type, while `Record` is a structure very similar to a dictionary in Python. It is a key-value pair data structure.
We've created a few components to help you work with these types. Let's see how a few of them work. We've created a few components to help you work with these types. Let's see how a few of them work.

798
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "langflow" name = "langflow"
version = "1.0.0a46" version = "1.0.0a43"
description = "A Python package with a built-in web application" description = "A Python package with a built-in web application"
authors = ["Langflow <contact@langflow.org>"] authors = ["Langflow <contact@langflow.org>"]
maintainers = [ maintainers = [
@ -81,7 +81,7 @@ langchain-google-vertexai = "^1.0.3"
langchain-groq = "^0.1.3" langchain-groq = "^0.1.3"
langchain-pinecone = "^0.1.0" langchain-pinecone = "^0.1.0"
langchain-mistralai = "^0.1.6" langchain-mistralai = "^0.1.6"
couchbase = { extras = ["couchbase"], version = "^4.2.1", optional = true } couchbase = "^4.2.1"
youtube-transcript-api = "^0.6.2" youtube-transcript-api = "^0.6.2"
markdown = "^3.6" markdown = "^3.6"
langchain-chroma = "^0.1.1" langchain-chroma = "^0.1.1"
@ -118,7 +118,6 @@ vulture = "^2.11"
[tool.poetry.extras] [tool.poetry.extras]
deploy = ["celery", "redis", "flower"] deploy = ["celery", "redis", "flower"]
couchbase = ["couchbase"]
local = ["llama-cpp-python", "sentence-transformers", "ctransformers"] local = ["llama-cpp-python", "sentence-transformers", "ctransformers"]
@ -141,7 +140,7 @@ testpaths = ["tests", "integration"]
console_output_style = "progress" console_output_style = "progress"
filterwarnings = ["ignore::DeprecationWarning"] filterwarnings = ["ignore::DeprecationWarning"]
log_cli = true log_cli = true
markers = ["async_test", "api_key_required"] markers = ["async_test"]
[tool.ruff] [tool.ruff]

View file

@ -1,9 +1,10 @@
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
from langflow.services.monitor.schema import ( from langflow.services.monitor.schema import (
MessageModelRequest,
MessageModelResponse, MessageModelResponse,
TransactionModelResponse, TransactionModelResponse,
VertexBuildMapModel, VertexBuildMapModel,
@ -66,6 +67,44 @@ async def get_messages(
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@router.delete("/messages", status_code=204)
async def delete_messages(
message_ids: List[int],
monitor_service: MonitorService = Depends(get_monitor_service),
):
try:
monitor_service.delete_messages(message_ids=message_ids)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/messages/{message_id}", response_model=MessageModelResponse)
async def update_message(
message_id: str,
message: MessageModelRequest,
monitor_service: MonitorService = Depends(get_monitor_service),
):
try:
message_dict = message.model_dump(exclude_none=True)
message_dict.pop("index", None)
monitor_service.update_message(message_id=message_id, **message_dict)
return MessageModelResponse(index=message_id, **message_dict)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/messages/session/{session_id}", status_code=204)
async def delete_messages_session(
session_id: str,
monitor_service: MonitorService = Depends(get_monitor_service),
):
try:
monitor_service.delete_messages_session(session_id=session_id)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/transactions", response_model=List[TransactionModelResponse]) @router.get("/transactions", response_model=List[TransactionModelResponse])
async def get_transactions( async def get_transactions(
source: Optional[str] = Query(None), source: Optional[str] = Query(None),

View file

@ -122,6 +122,13 @@ class MessageModelResponse(MessageModel):
return v return v
class MessageModelRequest(MessageModel):
message: str = Field(default="")
sender: str = Field(default="")
sender_name: str = Field(default="")
session_id: str = Field(default="")
class VertexBuildModel(BaseModel): class VertexBuildModel(BaseModel):
index: Optional[int] = Field(default=None, alias="index", exclude=True) index: Optional[int] = Field(default=None, alias="index", exclude=True)
id: Optional[str] = Field(default=None, alias="id") id: Optional[str] = Field(default=None, alias="id")

View file

@ -32,6 +32,10 @@ class MonitorService(Service):
except Exception as e: except Exception as e:
logger.exception(f"Error initializing monitor service: {e}") logger.exception(f"Error initializing monitor service: {e}")
def exec_query(self, query: str):
with duckdb.connect(str(self.db_path)) as conn:
return conn.execute(query).df()
def to_df(self, table_name): def to_df(self, table_name):
return self.load_table_as_dataframe(table_name) return self.load_table_as_dataframe(table_name)
@ -69,7 +73,7 @@ class MonitorService(Service):
valid: Optional[bool] = None, valid: Optional[bool] = None,
order_by: Optional[str] = "timestamp", order_by: Optional[str] = "timestamp",
): ):
query = "SELECT index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds" query = "SELECT id, index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds"
conditions = [] conditions = []
if flow_id: if flow_id:
conditions.append(f"flow_id = '{flow_id}'") conditions.append(f"flow_id = '{flow_id}'")
@ -88,6 +92,8 @@ class MonitorService(Service):
with duckdb.connect(str(self.db_path)) as conn: with duckdb.connect(str(self.db_path)) as conn:
df = conn.execute(query).df() df = conn.execute(query).df()
print(query)
return df.to_dict(orient="records") return df.to_dict(orient="records")
def delete_vertex_builds(self, flow_id: Optional[str] = None): def delete_vertex_builds(self, flow_id: Optional[str] = None):
@ -98,11 +104,20 @@ class MonitorService(Service):
with duckdb.connect(str(self.db_path)) as conn: with duckdb.connect(str(self.db_path)) as conn:
conn.execute(query) conn.execute(query)
def delete_messages(self, session_id: str): def delete_messages_session(self, session_id: str):
query = f"DELETE FROM messages WHERE session_id = '{session_id}'" query = f"DELETE FROM messages WHERE session_id = '{session_id}'"
with duckdb.connect(str(self.db_path)) as conn: return self.exec_query(query)
conn.execute(query)
def delete_messages(self, message_ids: list[int]):
query = f"DELETE FROM messages WHERE index IN ({','.join(map(str, message_ids))})"
return self.exec_query(query)
def update_message(self, message_id: int, **kwargs):
query = f"""UPDATE messages SET {', '.join(f"{k} = '{v}'" for k, v in kwargs.items())} WHERE index = {message_id}"""
return self.exec_query(query)
def add_message(self, message: MessageModel): def add_message(self, message: MessageModel):
self.add_row("messages", message) self.add_row("messages", message)

View file

@ -26,6 +26,7 @@
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6", "@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0", "@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6", "@tailwindcss/forms": "^0.5.6",
@ -2762,6 +2763,31 @@
} }
} }
}, },
"node_modules/@radix-ui/react-toggle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
"integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip": { "node_modules/@radix-ui/react-tooltip": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",

View file

@ -21,6 +21,7 @@
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6", "@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0", "@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6", "@tailwindcss/forms": "^0.5.6",

View file

@ -23,19 +23,19 @@ export default function AddNewVariableButton({ children }): JSX.Element {
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const componentFields = useTypesStore((state) => state.ComponentFields); const componentFields = useTypesStore((state) => state.ComponentFields);
const unavaliableFields = new Set( const unavaliableFields = new Set(
Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)) Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)),
); );
const availableFields = () => { const availableFields = () => {
const fields = Array.from(componentFields).filter( const fields = Array.from(componentFields).filter(
(field) => !unavaliableFields.has(field) (field) => !unavaliableFields.has(field),
); );
return sortByName(fields); return sortByName(fields);
}; };
const addGlobalVariable = useGlobalVariablesStore( const addGlobalVariable = useGlobalVariablesStore(
(state) => state.addGlobalVariable (state) => state.addGlobalVariable,
); );
function handleSaveVariable() { function handleSaveVariable() {

View file

@ -31,7 +31,7 @@ export default function InputListComponent({
<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",
)} )}
> >
{value.map((singleValue, idx) => { {value.map((singleValue, idx) => {

View file

@ -33,7 +33,7 @@ const SideBarFoldersButtonsComponent = ({
const [foldersNames, setFoldersNames] = useState({}); const [foldersNames, setFoldersNames] = useState({});
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
const [editFolders, setEditFolderName] = useState( const [editFolders, setEditFolderName] = useState(
folders.map((obj) => ({ name: obj.name, edit: false })) folders.map((obj) => ({ name: obj.name, edit: false })),
); );
const uploadFolder = useFolderStore((state) => state.uploadFolder); const uploadFolder = useFolderStore((state) => state.uploadFolder);
const currentFolder = pathname.split("/"); const currentFolder = pathname.split("/");
@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({
const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop( const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop(
folderId, folderId,
handleFolderChange handleFolderChange,
); );
const handleUploadFlowsToFolder = () => { const handleUploadFlowsToFolder = () => {
@ -73,7 +73,7 @@ const SideBarFoldersButtonsComponent = ({
addFolder({ name: "New Folder", parent_id: null, description: "" }).then( addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => { (res) => {
getFoldersApi(true); getFoldersApi(true);
} },
); );
} }
@ -119,7 +119,7 @@ const SideBarFoldersButtonsComponent = ({
<> <>
{folders.map((item, index) => { {folders.map((item, index) => {
const editFolderName = editFolders?.filter( const editFolderName = editFolders?.filter(
(folder) => folder.name === item.name (folder) => folder.name === item.name,
)[0]; )[0];
return ( return (
<div <div
@ -135,7 +135,7 @@ const SideBarFoldersButtonsComponent = ({
? "border border-border bg-muted hover:bg-muted" ? "border border-border bg-muted hover:bg-muted"
: "border hover:bg-transparent lg:border-transparent lg:hover:border-border", : "border hover:bg-transparent lg:border-transparent lg:hover:border-border",
"group flex w-full shrink-0 cursor-pointer gap-2 opacity-100 lg:min-w-full", "group flex w-full shrink-0 cursor-pointer gap-2 opacity-100 lg:min-w-full",
folderIdDragging === item.id! ? "bg-border" : "" folderIdDragging === item.id! ? "bg-border" : "",
)} )}
onClick={() => handleChangeFolder!(item.id!)} onClick={() => handleChangeFolder!(item.id!)}
> >
@ -205,7 +205,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({ folders.map((obj) => ({
name: obj.name, name: obj.name,
edit: false, edit: false,
})) })),
); );
} }
if (e.key === "Enter") { if (e.key === "Enter") {
@ -238,10 +238,10 @@ const SideBarFoldersButtonsComponent = ({
}; };
const updatedFolder = await updateFolder( const updatedFolder = await updateFolder(
body, body,
item.id! item.id!,
); );
const updateFolders = folders.filter( const updateFolders = folders.filter(
(f) => f.name !== item.name (f) => f.name !== item.name,
); );
setFolders([...updateFolders, updatedFolder]); setFolders([...updateFolders, updatedFolder]);
setFoldersNames({}); setFoldersNames({});
@ -249,7 +249,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({ folders.map((obj) => ({
name: obj.name, name: obj.name,
edit: false, edit: false,
})) })),
); );
} else { } else {
setFoldersNames((old) => ({ setFoldersNames((old) => ({

View file

@ -0,0 +1,31 @@
import { cn } from "../../../../utils/utils";
import ShadTooltip from "../../../shadTooltipComponent";
import { Toggle } from "../../../ui/toggle";
export default function ResetColumns({
resetGrid,
}: {
resetGrid: () => void;
}): JSX.Element {
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")}>
<span
className="cursor-pointer underline"
onClick={() => {
resetGrid();
}}
>
Reset Columns
</span>
</div>
);
}

View file

@ -1,22 +1,27 @@
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, useCallback } from "react"; import { ElementRef, forwardRef, useEffect, useRef } from "react";
import { import {
DEFAULT_TABLE_ALERT_MSG, DEFAULT_TABLE_ALERT_MSG,
DEFAULT_TABLE_ALERT_TITLE, DEFAULT_TABLE_ALERT_TITLE,
} from "../../constants/constants"; } from "../../constants/constants";
import { useDarkStore } from "../../stores/darkStore"; import { useDarkStore } from "../../stores/darkStore";
import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid
import { cn } 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";
interface TableComponentProps extends AgGridReactProps { interface TableComponentProps extends AgGridReactProps {
columnDefs: NonNullable<AgGridReactProps["columnDefs"]>; columnDefs: NonNullable<AgGridReactProps["columnDefs"]>;
rowData: NonNullable<AgGridReactProps["rowData"]>; rowData: NonNullable<AgGridReactProps["rowData"]>;
alertTitle?: string; alertTitle?: string;
alertDescription?: string; alertDescription?: string;
editable?: boolean | string[];
} }
const TableComponent = forwardRef< const TableComponent = forwardRef<
@ -31,7 +36,67 @@ const TableComponent = forwardRef<
}, },
ref, ref,
) => { ) => {
let colDef = props.columnDefs.map((col, index) => {
let newCol = {
...col,
headerName: toTitleCase(col.headerName),
};
if (index === props.columnDefs.length - 1) {
newCol = {
...newCol,
resizable: false,
};
}
if (props.onSelectionChanged && index === 0) {
newCol = {
...newCol,
checkboxSelection: true,
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
};
}
if (
(typeof props.editable === "boolean" && props.editable) ||
(Array.isArray(props.editable) &&
props.editable.includes(newCol.headerName ?? ""))
) {
newCol = {
...newCol,
editable: true,
};
}
return newCol;
});
const gridRef = useRef(null);
// @ts-ignore
const realRef = ref?.current ? ref : gridRef;
const dark = useDarkStore((state) => state.dark); const dark = useDarkStore((state) => state.dark);
const initialColumnDefs = useRef(colDef);
const makeLastColumnNonResizable = (columnDefs) => {
columnDefs.forEach((colDef, index) => {
colDef.resizable = index !== columnDefs.length - 1;
});
return columnDefs;
};
const onGridReady = (params) => {
// @ts-ignore
realRef.current = params;
const updatedColumnDefs = makeLastColumnNonResizable([...colDef]);
params.api.setColumnDefs(updatedColumnDefs);
initialColumnDefs.current = params.api.getColumnDefs();
if (props.onGridReady) props.onGridReady(params);
};
const onColumnMoved = (params) => {
const updatedColumnDefs = makeLastColumnNonResizable(
params.columnApi.getAllGridColumns().map((col) => col.getColDef()),
);
params.api.setColumnDefs(updatedColumnDefs);
if (props.onColumnMoved) props.onColumnMoved(params);
};
if (props.rowData.length === 0) { if (props.rowData.length === 0) {
return ( return (
<div className="flex h-full w-full items-center justify-center rounded-md border"> <div className="flex h-full w-full items-center justify-center rounded-md border">
@ -46,12 +111,12 @@ const TableComponent = forwardRef<
</div> </div>
); );
} }
return ( return (
<div <div
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",
)} // applying the grid theme )} // applying the grid theme
> >
<AgGridReact <AgGridReact
@ -60,8 +125,13 @@ const TableComponent = forwardRef<
defaultColDef={{ defaultColDef={{
minWidth: 100, minWidth: 100,
}} }}
ref={ref} columnDefs={colDef}
ref={realRef}
pagination={true}
onGridReady={onGridReady}
onColumnMoved={onColumnMoved}
/> />
<ResetColumns resetGrid={() => resetGrid(realRef, initialColumnDefs)} />
</div> </div>
); );
}, },

View file

@ -0,0 +1,12 @@
export default function resetGrid(ref, initialColumnDefs) {
if (ref?.current && ref?.current.api) {
ref.current.api.resetColumnState();
if (initialColumnDefs.current) {
const resetColumns = ref.current.api.applyColumnState({
state: initialColumnDefs.current,
applyOrder: true,
});
return resetColumns;
}
}
}

View file

@ -0,0 +1,45 @@
"use client";
import * as React from "react";
import * as TogglePrimitive from "@radix-ui/react-toggle";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../utils/utils";
const toggleVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-10 px-3",
sm: "h-9 px-2.5",
lg: "h-11 px-5",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
));
Toggle.displayName = TogglePrimitive.Root.displayName;
export { Toggle, toggleVariants };

View file

@ -48,7 +48,7 @@ function ApiInterceptor() {
} }
await clearBuildVerticesState(error); await clearBuildVerticesState(error);
return Promise.reject(error); return Promise.reject(error);
} },
); );
const isAuthorizedURL = (url) => { const isAuthorizedURL = (url) => {
@ -65,10 +65,10 @@ function ApiInterceptor() {
const parsedURL = new URL(url); const parsedURL = new URL(url);
const isDomainAllowed = authorizedDomains.some( const isDomainAllowed = authorizedDomains.some(
(domain) => parsedURL.origin === new URL(domain).origin (domain) => parsedURL.origin === new URL(domain).origin,
); );
const isEndpointAllowed = authorizedEndpoints.some((endpoint) => const isEndpointAllowed = authorizedEndpoints.some((endpoint) =>
parsedURL.pathname.includes(endpoint) parsedURL.pathname.includes(endpoint),
); );
return isDomainAllowed || isEndpointAllowed; return isDomainAllowed || isEndpointAllowed;
@ -96,7 +96,7 @@ function ApiInterceptor() {
}, },
(error) => { (error) => {
return Promise.reject(error); return Promise.reject(error);
} },
); );
return () => { return () => {
@ -128,7 +128,7 @@ function ApiInterceptor() {
if (error?.config?.headers) { if (error?.config?.headers) {
delete error.config.headers["Authorization"]; delete error.config.headers["Authorization"];
error.config.headers["Authorization"] = `Bearer ${cookies.get( error.config.headers["Authorization"] = `Bearer ${cookies.get(
"access_token_lf" "access_token_lf",
)}`; )}`;
const response = await axios.request(error.config); const response = await axios.request(error.config);
return response; return response;

View file

@ -28,6 +28,7 @@ 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.
@ -61,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 });
} }
@ -76,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,
@ -149,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}`, {
@ -327,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`);
} }
@ -340,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);
} }
@ -356,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);
@ -365,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`, {
@ -378,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,
@ -400,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) {
@ -462,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;
@ -503,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;
@ -577,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/`, {
@ -706,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;
@ -721,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/`;
@ -833,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}`, {
@ -917,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}`, {
@ -936,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
@ -956,19 +957,19 @@ 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,
); );
} }
export async function postBuildVertex( export async function postBuildVertex(
flowId: string, flowId: string,
vertexId: string, vertexId: string,
input_value: string input_value: 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
return await api.post( return await api.post(
`${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, `${BASE_URL_API}build/${flowId}/vertices/${vertexId}`,
input_value ? { inputs: { input_value: input_value } } : undefined input_value ? { inputs: { input_value: input_value } } : undefined,
); );
} }
@ -992,7 +993,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 };
@ -1006,7 +1007,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[][] = [];
@ -1029,7 +1030,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
@ -1039,7 +1040,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 };
@ -1052,16 +1053,47 @@ export async function getTransactionTable(
} }
export async function getMessagesTable( export async function getMessagesTable(
id: string,
mode: "intersection" | "union", mode: "intersection" | "union",
params = {} id?: string,
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> { excludedFields?: string[],
params = {},
): Promise<{ rows: Array<Message>; columns: Array<ColDef | ColGroupDef> }> {
const config = {}; const config = {};
config["params"] = { flow_id: id }; if (id) {
config["params"] = { flow_id: id };
}
if (params) { if (params) {
config["params"] = { ...config["params"], ...params }; config["params"] = { ...config["params"], ...params };
} }
const rows = await api.get(`${BASE_URL_API}monitor/messages`, config); const rows = await api.get(`${BASE_URL_API}monitor/messages`, config);
const columns = extractColumnsFromRows(rows.data, mode); const columns = extractColumnsFromRows(rows.data, mode, excludedFields);
return { rows: rows.data, columns }; return { rows: rows.data, columns };
} }
export async function getSessions(id?: string): Promise<Array<string>> {
const config = {};
if (id) {
config["params"] = { flow_id: id };
}
const rows = await api.get(`${BASE_URL_API}monitor/messages`, config);
const sessions = new Set<string>();
rows.data.forEach((row) => {
sessions.add(row.session_id);
});
return Array.from(sessions);
}
export async function deleteMessagesFn(ids: number[]) {
try {
return await api.delete(`${BASE_URL_API}monitor/messages`, {
data: ids,
});
} catch (error) {
console.error("Error deleting flows:", error);
throw error;
}
}
export async function updateMessageApi(data: Message) {
return await api.post(`${BASE_URL_API}monitor/messages/${data.index}`, data);
}

View file

@ -55,14 +55,14 @@ 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 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 [validationStatus, setValidationStatus] = const [validationStatus, setValidationStatus] =
useState<validationStatusType | null>(null); useState<validationStatusType | null>(null);
@ -115,7 +115,7 @@ export default function GenericNode({
updateNodeInternals(data.id); updateNodeInternals(data.id);
}, },
[data.id, data.node, setNode, setIsOutdated] [data.id, data.node, setNode, setIsOutdated],
); );
if (!data.node!.template) { if (!data.node!.template) {
@ -255,7 +255,7 @@ export default function GenericNode({
const isDark = useDarkStore((state) => state.dark); const isDark = useDarkStore((state) => state.dark);
const renderIconStatus = ( const renderIconStatus = (
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null validationStatus: validationStatusType | null,
) => { ) => {
if (buildStatus === BuildStatus.BUILDING) { if (buildStatus === BuildStatus.BUILDING) {
return <Loading className="text-medium-indigo" />; return <Loading className="text-medium-indigo" />;
@ -296,7 +296,7 @@ export default function GenericNode({
}; };
const getSpecificClassFromBuildStatus = ( const getSpecificClassFromBuildStatus = (
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null validationStatus: validationStatusType | null,
) => { ) => {
let isInvalid = validationStatus && !validationStatus.valid; let isInvalid = validationStatus && !validationStatus.valid;
@ -320,11 +320,11 @@ export default function GenericNode({
selected: boolean, selected: boolean,
showNode: boolean, showNode: boolean,
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null validationStatus: validationStatusType | null,
) => { ) => {
const specificClassFromBuildStatus = getSpecificClassFromBuildStatus( const specificClassFromBuildStatus = getSpecificClassFromBuildStatus(
buildStatus, buildStatus,
validationStatus validationStatus,
); );
const baseBorderClass = getBaseBorderClass(selected); const baseBorderClass = getBaseBorderClass(selected);
@ -333,7 +333,7 @@ export default function GenericNode({
baseBorderClass, baseBorderClass,
nodeSizeClass, nodeSizeClass,
"generic-node-div", "generic-node-div",
specificClassFromBuildStatus specificClassFromBuildStatus,
); );
return names; return names;
}; };
@ -393,7 +393,7 @@ export default function GenericNode({
selected, selected,
showNode, showNode,
buildStatus, buildStatus,
validationStatus validationStatus,
)} )}
> >
{data.node?.beta && showNode && ( {data.node?.beta && showNode && (
@ -524,7 +524,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}
@ -552,7 +552,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({
@ -709,7 +709,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);
@ -771,13 +771,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}
@ -804,7 +804,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

@ -9,7 +9,7 @@ const useFetchDataOnMount = (
handleUpdateValues, handleUpdateValues,
setNode, setNode,
renderTooltips, renderTooltips,
setIsLoading setIsLoading,
) => { ) => {
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);

View file

@ -10,7 +10,7 @@ const useHandleOnNewValue = (
debouncedHandleUpdateValues, debouncedHandleUpdateValues,
setNode, setNode,
renderTooltips, renderTooltips,
setIsLoading setIsLoading,
) => { ) => {
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);

View file

@ -1,5 +1,11 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import IconComponent from "../../../../components/genericIconComponent"; import IconComponent from "../../../../components/genericIconComponent";
import {
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,
@ -118,10 +124,21 @@ export default function ChatView({
if (lockChat) setLockChat(false); if (lockChat) setLockChat(false);
} }
function handleSelectChange(event: string): void {
switch (event) {
case "builds":
clearChat();
break;
case "buildsNSession":
console.log("delete build and session");
break;
}
}
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;
@ -149,18 +166,57 @@ 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 disabled={lockChat} onClick={() => clearChat()}> <button
className="flex gap-1"
onClick={() => handleSelectChange("builds")}
>
<IconComponent <IconComponent
name="Eraser" name="Eraser"
className={classNames( className={classNames(
"h-5 w-5", "h-5 w-5 transition-all duration-100",
lockChat lockChat ? "animate-pulse text-primary" : "text-primary",
? "animate-pulse text-primary"
: "text-primary hover:text-gray-600"
)} )}
aria-hidden="true" aria-hidden="true"
/> />
</button> </button>
{/* <Select
onValueChange={handleSelectChange}
value=""
disabled={lockChat}
>
<SelectTrigger className="">
<button className="flex gap-1">
<IconComponent
name="Eraser"
className={classNames(
"h-5 w-5 transition-all duration-100",
lockChat ? "animate-pulse text-primary" : "text-primary",
)}
aria-hidden="true"
/>
</button>
</SelectTrigger>
<SelectContent className="right-[9.5em]">
<SelectItem value="builds" className="cursor-pointer">
<div className="flex">
<IconComponent
name={"Trash2"}
className={`relative top-0.5 mr-2 h-4 w-4`}
/>
<span className="">Clear Builds</span>
</div>
</SelectItem>
<SelectItem value="buildsNSession" className="cursor-pointer">
<div className="flex">
<IconComponent
name={"Trash2"}
className={`relative top-0.5 mr-2 h-4 w-4`}
/>
<span className="">Clear Builds & Session</span>
</div>
</SelectItem>
</SelectContent>
</Select> */}
</div> </div>
<div ref={messagesRef} className="chat-message-div"> <div ref={messagesRef} className="chat-message-div">
{chatHistory?.length > 0 ? ( {chatHistory?.length > 0 ? (

View file

@ -24,6 +24,7 @@ import { cn } from "../../utils/utils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
import IOFieldView from "./components/IOFieldView"; import IOFieldView from "./components/IOFieldView";
import ChatView from "./components/chatView"; import ChatView from "./components/chatView";
import { getSessions } from "../../controllers/API";
export default function IOModal({ export default function IOModal({
children, children,
@ -77,6 +78,7 @@ export default function IOModal({
const isBuilding = useFlowStore((state) => state.isBuilding); const isBuilding = useFlowStore((state) => state.isBuilding);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
const [sessions, setSessions] = useState<string[]>([]);
async function updateVertices() { async function updateVertices() {
return updateVerticesOrder(currentFlow!.id, null); return updateVerticesOrder(currentFlow!.id, null);
@ -113,6 +115,11 @@ export default function IOModal({
useEffect(() => { useEffect(() => {
setSelectedViewField(startView()); setSelectedViewField(startView());
// if (haveChat) {
// getSessions().then((sessions) => {
// setSessions(sessions);
// });
// }
}, [open]); }, [open]);
return ( return (
@ -161,6 +168,9 @@ export default function IOModal({
{outputs.length > 0 && ( {outputs.length > 0 && (
<TabsTrigger value={"2"}>Outputs</TabsTrigger> <TabsTrigger value={"2"}>Outputs</TabsTrigger>
)} )}
{/* {haveChat && (
<TabsTrigger value={"3"}>History</TabsTrigger>
)} */}
</TabsList> </TabsList>
</div> </div>

View file

@ -9,7 +9,7 @@ export default function getPythonApiCode(
flowId: string, flowId: string,
isAuth: boolean, isAuth: boolean,
tweaksBuildedObject, tweaksBuildedObject,
endpointName?: string endpointName?: string,
): string { ): string {
const tweaksObject = tweaksBuildedObject[0]; const tweaksObject = tweaksBuildedObject[0];
return `import argparse return `import argparse

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,18 +50,18 @@ 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);
@ -77,7 +77,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 +126,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 +143,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 +185,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 +229,7 @@ const ApiModal = forwardRef(
</BaseModal.Content> </BaseModal.Content>
</BaseModal> </BaseModal>
); );
} },
); );
export default ApiModal; export default ApiModal;

View file

@ -52,7 +52,7 @@ const EditNodeModal = forwardRef(
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void;
data: NodeDataType; data: NodeDataType;
}, },
ref ref,
) => { ) => {
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
@ -134,7 +134,7 @@ const EditNodeModal = forwardRef(
"edit-node-modal-box", "edit-node-modal-box",
nodeLength > limitScrollFieldsModal nodeLength > limitScrollFieldsModal
? "overflow-scroll overflow-x-hidden custom-scroll" ? "overflow-scroll overflow-x-hidden custom-scroll"
: "" : "",
)} )}
> >
{nodeLength > 0 && ( {nodeLength > 0 && (
@ -157,8 +157,8 @@ const EditNodeModal = forwardRef(
templateParam.charAt(0) !== "_" && templateParam.charAt(0) !== "_" &&
myData.node?.template[templateParam].show && myData.node?.template[templateParam].show &&
LANGFLOW_SUPPORTED_TYPES.has( LANGFLOW_SUPPORTED_TYPES.has(
myData.node!.template[templateParam].type myData.node!.template[templateParam].type,
) ),
) )
.map((templateParam, index) => { .map((templateParam, index) => {
let id = { let id = {
@ -180,8 +180,8 @@ const EditNodeModal = forwardRef(
myData.node?.template[templateParam] myData.node?.template[templateParam]
.proxy, .proxy,
} }
: id : id,
) ),
) ?? false; ) ?? false;
return ( return (
<TableRow <TableRow
@ -204,11 +204,11 @@ const EditNodeModal = forwardRef(
? myData.node?.template[templateParam] ? myData.node?.template[templateParam]
.proxy?.id .proxy?.id
: myData.node?.template[templateParam] : myData.node?.template[templateParam]
.display_name .display_name
? myData.node!.template[templateParam] ? myData.node!.template[templateParam]
.display_name .display_name
: myData.node?.template[templateParam] : myData.node?.template[templateParam]
.name .name
} }
> >
<span> <span>
@ -263,7 +263,7 @@ const EditNodeModal = forwardRef(
onChange={(value: string[]) => { onChange={(value: string[]) => {
handleOnNewValue( handleOnNewValue(
value, value,
templateParam templateParam,
); );
}} }}
/> />
@ -287,11 +287,11 @@ const EditNodeModal = forwardRef(
.value ?? "" .value ?? ""
} }
onChange={( onChange={(
value: string | string[] value: string | string[],
) => { ) => {
handleOnNewValue( handleOnNewValue(
value, value,
templateParam templateParam,
); );
}} }}
/> />
@ -341,7 +341,7 @@ const EditNodeModal = forwardRef(
].value = newValue; ].value = newValue;
handleOnNewValue( handleOnNewValue(
newValue, newValue,
templateParam templateParam,
); );
}} }}
id="editnode-div-dict-input" id="editnode-div-dict-input"
@ -358,7 +358,7 @@ const EditNodeModal = forwardRef(
myData.node!.template[templateParam].value myData.node!.template[templateParam].value
?.length > 1 ?.length > 1
? "my-3" ? "my-3"
: "" : "",
)} )}
> >
<KeypairListComponent <KeypairListComponent
@ -374,7 +374,7 @@ const EditNodeModal = forwardRef(
myData.node!.template[ myData.node!.template[
templateParam templateParam
].value, ].value,
type(templateParam)! type(templateParam)!,
) )
} }
duplicateKey={errorDuplicateKey} duplicateKey={errorDuplicateKey}
@ -385,11 +385,11 @@ const EditNodeModal = forwardRef(
templateParam templateParam
].value = valueToNumbers; ].value = valueToNumbers;
setErrorDuplicateKey( setErrorDuplicateKey(
hasDuplicateKeys(valueToNumbers) hasDuplicateKeys(valueToNumbers),
); );
handleOnNewValue( handleOnNewValue(
valueToNumbers, valueToNumbers,
templateParam templateParam,
); );
}} }}
isList={ isList={
@ -419,7 +419,7 @@ const EditNodeModal = forwardRef(
setEnabled={(isEnabled) => { setEnabled={(isEnabled) => {
handleOnNewValue( handleOnNewValue(
isEnabled, isEnabled,
templateParam templateParam,
); );
}} }}
size="small" size="small"
@ -643,7 +643,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

@ -33,11 +33,13 @@ export default function FlowLogsModal({
setRows(rows); setRows(rows);
}); });
} else if (activeTab === "Messages") { } else if (activeTab === "Messages") {
getMessagesTable(currentFlowId, "union").then((data) => { getMessagesTable("union", currentFlowId, ["index", "flow_id"]).then(
const { columns, rows } = data; (data) => {
setColumns(columns.map((col) => ({ ...col, editable: true }))); const { columns, rows } = data;
setRows(rows); setColumns(columns.map((col) => ({ ...col, editable: true })));
}); setRows(rows);
},
);
} }
if (open && activeTab === "Messages" && !noticed.current) { if (open && activeTab === "Messages" && !noticed.current) {

View file

@ -58,7 +58,7 @@ export default function NodeToolbarComponent({
data.node.template[templateField].type === "Any" || data.node.template[templateField].type === "Any" ||
data.node.template[templateField].type === "int" || data.node.template[templateField].type === "int" ||
data.node.template[templateField].type === "dict" || data.node.template[templateField].type === "dict" ||
data.node.template[templateField].type === "NestedDict") data.node.template[templateField].type === "NestedDict"),
).length; ).length;
const templates = useTypesStore((state) => state.templates); const templates = useTypesStore((state) => state.templates);
const hasStore = useStoreStore((state) => state.hasStore); const hasStore = useStoreStore((state) => state.hasStore);
@ -85,7 +85,7 @@ export default function NodeToolbarComponent({
const [showconfirmShare, setShowconfirmShare] = useState(false); const [showconfirmShare, setShowconfirmShare] = useState(false);
const [showOverrideModal, setShowOverrideModal] = useState(false); const [showOverrideModal, setShowOverrideModal] = useState(false);
const [flowComponent, setFlowComponent] = useState<FlowType>( const [flowComponent, setFlowComponent] = useState<FlowType>(
createFlowComponent(cloneDeep(data), version) createFlowComponent(cloneDeep(data), version),
); );
const openInNewTab = (url) => { const openInNewTab = (url) => {
@ -100,7 +100,7 @@ export default function NodeToolbarComponent({
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const setLastCopiedSelection = useFlowStore( const setLastCopiedSelection = useFlowStore(
(state) => state.setLastCopiedSelection (state) => state.setLastCopiedSelection,
); );
const setSuccessData = useAlertStore((state) => state.setSuccessData); const setSuccessData = useAlertStore((state) => state.setSuccessData);
@ -153,7 +153,7 @@ export default function NodeToolbarComponent({
nodes, nodes,
edges, edges,
setNodes, setNodes,
setEdges setEdges,
); );
break; break;
case "override": case "override":
@ -177,7 +177,7 @@ export default function NodeToolbarComponent({
y: 10, y: 10,
paneX: nodes.find((node) => node.id === data.id)?.position.x, paneX: nodes.find((node) => node.id === data.id)?.position.x,
paneY: nodes.find((node) => node.id === data.id)?.position.y, paneY: nodes.find((node) => node.id === data.id)?.position.y,
} },
); );
break; break;
case "update": case "update":
@ -215,13 +215,13 @@ export default function NodeToolbarComponent({
}; };
const isSaved = flows.some((flow) => const isSaved = flows.some((flow) =>
Object.values(flow).includes(data.node?.display_name!) Object.values(flow).includes(data.node?.display_name!),
); );
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
const handleOnNewValue = ( const handleOnNewValue = (
newValue: string | string[] | boolean | Object[] newValue: string | string[] | boolean | Object[],
): void => { ): void => {
if (data.node!.template[name].value !== newValue) { if (data.node!.template[name].value !== newValue) {
takeSnapshot(); takeSnapshot();
@ -408,7 +408,7 @@ export default function NodeToolbarComponent({
data-testid="save-button-modal" data-testid="save-button-modal"
className={classNames( className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10", "relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
hasCode ? " " : " rounded-l-md " hasCode ? " " : " rounded-l-md ",
)} )}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -426,7 +426,7 @@ export default function NodeToolbarComponent({
<button <button
data-testid="duplicate-button-modal" data-testid="duplicate-button-modal"
className={classNames( className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" "relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
)} )}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -440,7 +440,7 @@ export default function NodeToolbarComponent({
<ShadTooltip content="Freeze" side="top"> <ShadTooltip content="Freeze" side="top">
<button <button
className={classNames( className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" "relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
)} )}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -461,7 +461,7 @@ export default function NodeToolbarComponent({
className={cn( className={cn(
"h-4 w-4 transition-all", "h-4 w-4 transition-all",
// TODO UPDATE THIS COLOR TO BE A VARIABLE // TODO UPDATE THIS COLOR TO BE A VARIABLE
frozen ? "animate-wiggle text-ice" : "" frozen ? "animate-wiggle text-ice" : "",
)} )}
/> />
</button> </button>
@ -474,7 +474,7 @@ export default function NodeToolbarComponent({
<div <div
data-testid="more-options-modal" data-testid="more-options-modal"
className={classNames( className={classNames(
"relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" "relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
)} )}
> >
<IconComponent <IconComponent

View file

@ -46,6 +46,13 @@ export default function SettingsPage(): JSX.Element {
/> />
), ),
}, },
{
title: "Messages",
href: "/settings/messages",
icon: (
<ForwardedIconComponent name="Keyboard" className="w-5 stroke-[1.5]" />
),
},
]; ];
return ( return (
<PageLayout <PageLayout

View file

@ -78,9 +78,6 @@ export default function GlobalVariablesPage() {
// Column Definitions: Defines the columns to be displayed. // Column Definitions: Defines the columns to be displayed.
const [colDefs, setColDefs] = useState<(ColDef<any> | ColGroupDef<any>)[]>([ const [colDefs, setColDefs] = useState<(ColDef<any> | ColGroupDef<any>)[]>([
{ {
headerCheckboxSelection: true,
checkboxSelection: true,
showDisabledCheckboxes: true,
headerName: "Variable Name", headerName: "Variable Name",
field: "name", field: "name",
flex: 2, flex: 2,

View file

@ -9,7 +9,7 @@ const usePatchGradient = (
setSuccessData, setSuccessData,
setErrorData, setErrorData,
currentUserData, currentUserData,
setUserData setUserData,
) => { ) => {
const handlePatchGradient = async (gradient) => { const handlePatchGradient = async (gradient) => {
try { try {

View file

@ -11,7 +11,7 @@ const useSaveKey = (
setErrorData, setErrorData,
setHasApiKey, setHasApiKey,
setValidApiKey, setValidApiKey,
setLoadingApiKey setLoadingApiKey,
) => { ) => {
const { storeApiKey } = useContext(AuthContext); const { storeApiKey } = useContext(AuthContext);
@ -35,7 +35,7 @@ const useSaveKey = (
setHasApiKey(false); setHasApiKey(false);
setValidApiKey(false); setValidApiKey(false);
setLoadingApiKey(false); setLoadingApiKey(false);
} },
); );
} }
}; };

View file

@ -0,0 +1,49 @@
import ForwardedIconComponent from "../../../../../../components/genericIconComponent";
import { Button } from "../../../../../../components/ui/button";
import { cn } from "../../../../../../utils/utils";
type HeaderMessagesComponentProps = {
selectedRows: number[];
handleRemoveMessages: () => void;
};
const HeaderMessagesComponent = ({
selectedRows,
handleRemoveMessages,
}: HeaderMessagesComponentProps) => {
return (
<>
<div className="flex w-full items-center justify-between gap-4 space-y-0.5">
<div className="flex w-full flex-col">
<h2 className="flex items-center text-lg font-semibold tracking-tight">
Messages
<ForwardedIconComponent
name="MessagesSquare"
className="ml-2 h-5 w-5 text-primary"
/>
</h2>
<p className="text-sm text-muted-foreground">
Inspect, edit and remove messages to explore and refine model
behaviors.
</p>
</div>
<div className="flex flex-shrink-0 items-center gap-2">
<Button
data-testid="api-key-button-store"
variant="primary"
className="group px-2"
disabled={selectedRows.length === 0}
onClick={handleRemoveMessages}
>
<ForwardedIconComponent
name="Trash2"
className={cn(
"h-5 w-5 text-destructive group-disabled:text-primary",
)}
/>
</Button>
</div>
</div>
</>
);
};
export default HeaderMessagesComponent;

View file

@ -0,0 +1,24 @@
import { useEffect } from "react";
import { getMessagesTable } from "../../../../../controllers/API";
import { useMessagesStore } from "../../../../../stores/messagesStore";
const useMessagesTable = (setColumns) => {
const setMessages = useMessagesStore((state) => state.setMessages);
useEffect(() => {
const fetchData = async () => {
try {
const data = await getMessagesTable("union", undefined, ["index"]);
const { columns, rows } = data;
setColumns(columns);
setMessages(rows);
} catch (error) {
console.error("Error fetching messages:", error);
}
};
fetchData();
}, []);
return null;
};
export default useMessagesTable;

View file

@ -0,0 +1,30 @@
import { deleteMessagesFn } from "../../../../../controllers/API";
import { useMessagesStore } from "../../../../../stores/messagesStore";
const useRemoveMessages = (
setSelectedRows,
setSuccessData,
setErrorData,
selectedRows,
) => {
const deleteMessages = useMessagesStore((state) => state.removeMessages);
const handleRemoveMessages = async () => {
try {
await deleteMessagesFn(selectedRows);
deleteMessages(selectedRows);
setSelectedRows([]);
setSuccessData({
title: "Messages deleted successfully.",
});
} catch (error) {
setErrorData({
title: "Error deleting messages.",
});
}
};
return { handleRemoveMessages };
};
export default useRemoveMessages;

View file

@ -0,0 +1,29 @@
import { useMessagesStore } from "../../../../../stores/messagesStore";
import { Message } from "../../../../../types/messages";
import { updateMessageApi } from "../../../../../controllers/API";
const useUpdateMessage = (setSuccessData, setErrorData) => {
const updateMessage = useMessagesStore((state) => state.updateMessage);
const handleUpdate = async (data: Message) => {
try {
await updateMessageApi(data);
updateMessage(data);
// Set success message
setSuccessData({
title: "Messages updated successfully.",
});
} catch (error) {
// Set error message
setErrorData({
title: "Error updating messages.",
});
}
};
return { handleUpdate };
};
export default useUpdateMessage;

View file

@ -0,0 +1,81 @@
import {
CellEditRequestEvent,
ColDef,
ColGroupDef,
SelectionChangedEvent,
} from "ag-grid-community";
import { useState } from "react";
import TableComponent from "../../../../components/tableComponent";
import { Card, CardContent } from "../../../../components/ui/card";
import useAlertStore from "../../../../stores/alertStore";
import { useMessagesStore } from "../../../../stores/messagesStore";
import HeaderMessagesComponent from "./components/headerMessages";
import useMessagesTable from "./hooks/use-messages-table";
import useRemoveMessages from "./hooks/use-remove-messages";
import useUpdateMessage from "./hooks/use-updateMessage";
export default function MessagesPage() {
const [columns, setColumns] = useState<Array<ColDef | ColGroupDef>>([]);
const messages = useMessagesStore((state) => state.messages);
const setErrorData = useAlertStore((state) => state.setErrorData);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const [selectedRows, setSelectedRows] = useState<number[]>([]);
const { handleRemoveMessages } = useRemoveMessages(
setSelectedRows,
setSuccessData,
setErrorData,
selectedRows,
);
const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData);
useMessagesTable(setColumns);
function handleUpdateMessage(event: CellEditRequestEvent<any, string>) {
const newValue = event.newValue;
const field = event.column.getColId();
const row = event.data;
const data = {
...row,
[field]: newValue,
};
handleUpdate(data);
}
return (
<div className="flex h-full w-full flex-col justify-between gap-6">
<HeaderMessagesComponent
selectedRows={selectedRows}
handleRemoveMessages={handleRemoveMessages}
/>
<div className="flex h-full w-full flex-col justify-between pb-8">
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
<CardContent className="h-full">
<TableComponent
readOnlyEdit
onCellEditRequest={(event) => {
handleUpdateMessage(event);
}}
editable={["Sender Name", "Message"]}
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(
event.api.getSelectedRows().map((row) => row.index),
);
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={columns}
rowData={messages}
/>
</CardContent>
</Card>
</div>
</div>
);
}

View file

@ -6,6 +6,7 @@ import { ProtectedLoginRoute } from "./components/authLoginGuard";
import { CatchAllRoute } from "./components/catchAllRoutes"; import { CatchAllRoute } from "./components/catchAllRoutes";
import LoadingComponent from "./components/loadingComponent"; import LoadingComponent from "./components/loadingComponent";
import { StoreGuard } from "./components/storeGuard"; import { StoreGuard } from "./components/storeGuard";
import MessagesPage from "./pages/SettingsPage/pages/messagesPage";
const AdminPage = lazy(() => import("./pages/AdminPage")); const AdminPage = lazy(() => import("./pages/AdminPage"));
const LoginAdminPage = lazy(() => import("./pages/AdminPage/LoginPage")); const LoginAdminPage = lazy(() => import("./pages/AdminPage/LoginPage"));
@ -78,6 +79,7 @@ const Router = () => {
<Route path="global-variables" element={<GlobalVariablesPage />} /> <Route path="global-variables" element={<GlobalVariablesPage />} />
<Route path="general/:scrollId?" element={<GeneralPage />} /> <Route path="general/:scrollId?" element={<GeneralPage />} />
<Route path="shortcuts" element={<ShortcutsPage />} /> <Route path="shortcuts" element={<ShortcutsPage />} />
<Route path="messages" element={<MessagesPage />} />
</Route> </Route>
<Route <Route
path="/store" path="/store"

View file

@ -0,0 +1,43 @@
import { create } from "zustand";
import { MessagesStoreType } from "../types/zustand/messages";
export const useMessagesStore = create<MessagesStoreType>((set, get) => ({
messages: [],
setMessages: (messages) => {
set(() => ({ messages: messages }));
},
addMessage: (message) => {
set(() => ({ messages: [...get().messages, message] }));
},
removeMessage: (message) => {
set(() => ({
messages: get().messages.filter((msg) => msg.id !== message.id),
}));
},
updateMessage: (message) => {
set(() => ({
messages: get().messages.map((msg) =>
msg.index === message.index ? message : msg,
),
}));
},
clearMessages: () => {
set(() => ({ messages: [] }));
},
removeMessages: (ids) => {
return new Promise((resolve, reject) => {
try {
set((state) => {
const updatedMessages = state.messages.filter(
(msg) => !ids.includes(msg.index),
);
get().setMessages(updatedMessages);
resolve(updatedMessages);
return { messages: updatedMessages };
});
} catch (error) {
reject(error);
}
});
},
}));

View file

@ -15,6 +15,10 @@ pre {
font-family: inherit; font-family: inherit;
} }
.ag-paging-page-size {
display: none;
}
.react-flow__pane { .react-flow__pane {
cursor: default; cursor: default;
} }

View file

@ -756,3 +756,17 @@ export type toolbarSelectItemProps = {
dataTestId: string; dataTestId: string;
ping?: boolean; ping?: boolean;
}; };
export type clearChatPropsType = {
lockChat: boolean;
setLockChat: (lock: boolean) => void;
setChatHistory: (chatHistory: ChatMessageType) => void;
method: string;
};
export type handleSelectPropsType = {
event: string;
lockChat: boolean;
setLockChat: (lock: boolean) => void;
setChatHistory: (chatHistory: ChatMessageType) => void;
};

View file

@ -0,0 +1,13 @@
type Message = {
artifacts: Record<string, any>;
flow_id: string;
index: number;
message: string;
sender: string;
sender_name: string;
session_id: string;
timestamp: string;
id: string;
};
export type { Message };

View file

@ -48,8 +48,16 @@ export type FlowStoreType = {
onFlowPage: boolean; onFlowPage: boolean;
setOnFlowPage: (onFlowPage: boolean) => void; setOnFlowPage: (onFlowPage: boolean) => void;
flowPool: FlowPoolType; flowPool: FlowPoolType;
inputs: Array<{ type: string; id: string; displayName: string }>; inputs: Array<{
outputs: Array<{ type: string; id: string; displayName: string }>; type: string;
id: string;
displayName: string;
}>;
outputs: Array<{
type: string;
id: string;
displayName: string;
}>;
hasIO: boolean; hasIO: boolean;
setFlowPool: (flowPool: FlowPoolType) => void; setFlowPool: (flowPool: FlowPoolType) => void;
addDataToFlowPool: (data: FlowPoolObjectType, nodeId: string) => void; addDataToFlowPool: (data: FlowPoolObjectType, nodeId: string) => void;

View file

@ -0,0 +1,11 @@
import { Message } from "../../messages";
export type MessagesStoreType = {
messages: Message[];
setMessages: (messages: Message[]) => void;
addMessage: (message: Message) => void;
removeMessage: (message: Message) => void;
updateMessage: (message: Message) => void;
clearMessages: () => void;
removeMessages: (ids: number[]) => void;
};

View file

@ -99,18 +99,18 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) {
export function isValidConnection( export function isValidConnection(
{ source, target, sourceHandle, targetHandle }: Connection, { source, target, sourceHandle, targetHandle }: Connection,
nodes: Node[], nodes: Node[],
edges: Edge[] edges: Edge[],
) { ) {
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!); const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!); const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
if ( if (
targetHandleObject.inputTypes?.some( targetHandleObject.inputTypes?.some(
(n) => n === sourceHandleObject.dataType (n) => n === sourceHandleObject.dataType,
) || ) ||
sourceHandleObject.baseClasses.some( sourceHandleObject.baseClasses.some(
(t) => (t) =>
targetHandleObject.inputTypes?.some((n) => n === t) || targetHandleObject.inputTypes?.some((n) => n === t) ||
t === targetHandleObject.type t === targetHandleObject.type,
) )
) { ) {
let targetNode = nodes.find((node) => node.id === target!)?.data?.node; let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
@ -143,7 +143,7 @@ export function removeApiKeys(flow: FlowType): FlowType {
export function updateTemplate( export function updateTemplate(
reference: APITemplateType, reference: APITemplateType,
objectToUpdate: APITemplateType objectToUpdate: APITemplateType,
): APITemplateType { ): APITemplateType {
let clonedObject: APITemplateType = cloneDeep(reference); let clonedObject: APITemplateType = cloneDeep(reference);
@ -203,7 +203,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
export function updateIds( export function updateIds(
{ edges, nodes }: { edges: Edge[]; nodes: Node[] }, { edges, nodes }: { edges: Edge[]; nodes: Node[] },
selection?: { edges: Edge[]; nodes: Node[] } selection?: { edges: Edge[]; nodes: Node[] },
) { ) {
let idsMap = {}; let idsMap = {};
const selectionIds = selection?.nodes.map((n) => n.id); const selectionIds = selection?.nodes.map((n) => n.id);
@ -231,7 +231,7 @@ export function updateIds(
edge.source = idsMap[edge.source]; edge.source = idsMap[edge.source];
edge.target = idsMap[edge.target]; edge.target = idsMap[edge.target];
const sourceHandleObject: sourceHandleType = scapeJSONParse( const sourceHandleObject: sourceHandleType = scapeJSONParse(
edge.sourceHandle! edge.sourceHandle!,
); );
edge.sourceHandle = scapedJSONStringfy({ edge.sourceHandle = scapedJSONStringfy({
...sourceHandleObject, ...sourceHandleObject,
@ -241,7 +241,7 @@ export function updateIds(
edge.data.sourceHandle.id = edge.source; edge.data.sourceHandle.id = edge.source;
} }
const targetHandleObject: targetHandleType = scapeJSONParse( const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle! edge.targetHandle!,
); );
edge.targetHandle = scapedJSONStringfy({ edge.targetHandle = scapedJSONStringfy({
...targetHandleObject, ...targetHandleObject,
@ -287,11 +287,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
(scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName === (scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName ===
t && t &&
(scapeJSONParse(edge.targetHandle!) as targetHandleType).id === (scapeJSONParse(edge.targetHandle!) as targetHandleType).id ===
node.id node.id,
) )
) { ) {
errors.push( errors.push(
`${displayName || type} is missing ${getFieldTitle(template, t)}.` `${displayName || type} is missing ${getFieldTitle(template, t)}.`,
); );
} else if ( } else if (
template[t].type === "dict" && template[t].type === "dict" &&
@ -305,15 +305,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
errors.push( errors.push(
`${displayName || type} (${getFieldTitle( `${displayName || type} (${getFieldTitle(
template, template,
t t,
)}) contains duplicate keys with the same values.` )}) contains duplicate keys with the same values.`,
); );
if (hasEmptyKey(template[t].value)) if (hasEmptyKey(template[t].value))
errors.push( errors.push(
`${displayName || type} (${getFieldTitle( `${displayName || type} (${getFieldTitle(
template, template,
t t,
)}) field must not be empty.` )}) field must not be empty.`,
); );
} }
return errors; return errors;
@ -322,7 +322,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
export function validateNodes( export function validateNodes(
nodes: Node[], nodes: Node[],
edges: Edge[] edges: Edge[],
): // this returns an array of tuples with the node id and the errors ): // this returns an array of tuples with the node id and the errors
Array<{ id: string; errors: Array<string> }> { Array<{ id: string; errors: Array<string> }> {
if (nodes.length === 0) { if (nodes.length === 0) {
@ -343,7 +343,7 @@ export function updateEdges(edges: Edge[]) {
if (edges) if (edges)
edges.forEach((edge) => { edges.forEach((edge) => {
const targetHandleObject: targetHandleType = scapeJSONParse( const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle! edge.targetHandle!,
); );
edge.className = "stroke-gray-900 stroke-connection"; edge.className = "stroke-gray-900 stroke-connection";
}); });
@ -410,7 +410,7 @@ export function handleKeyDown(
| React.KeyboardEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>
| React.KeyboardEvent<HTMLTextAreaElement>, | React.KeyboardEvent<HTMLTextAreaElement>,
inputValue: string | string[] | null, inputValue: string | string[] | null,
block: string block: string,
) { ) {
//condition to fix bug control+backspace on Windows/Linux //condition to fix bug control+backspace on Windows/Linux
if ( if (
@ -435,7 +435,7 @@ export function handleKeyDown(
} }
export function handleOnlyIntegerInput( export function handleOnlyIntegerInput(
event: React.KeyboardEvent<HTMLInputElement> event: React.KeyboardEvent<HTMLInputElement>,
) { ) {
if ( if (
event.key === "." || event.key === "." ||
@ -451,7 +451,7 @@ export function handleOnlyIntegerInput(
export function getConnectedNodes( export function getConnectedNodes(
edge: Edge, edge: Edge,
nodes: Array<NodeType> nodes: Array<NodeType>,
): Array<NodeType> { ): Array<NodeType> {
const sourceId = edge.source; const sourceId = edge.source;
const targetId = edge.target; const targetId = edge.target;
@ -552,7 +552,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean {
!edge.sourceHandle || !edge.sourceHandle ||
!edge.targetHandle || !edge.targetHandle ||
!edge.sourceHandle.includes("{") || !edge.sourceHandle.includes("{") ||
!edge.targetHandle.includes("{") !edge.targetHandle.includes("{"),
); );
} }
@ -575,7 +575,7 @@ export function customStringify(obj: any): string {
const keys = Object.keys(obj).sort(); const keys = Object.keys(obj).sort();
const keyValuePairs = keys.map( const keyValuePairs = keys.map(
(key) => `"${key}":${customStringify(obj[key])}` (key) => `"${key}":${customStringify(obj[key])}`,
); );
return `{${keyValuePairs.join(",")}}`; return `{${keyValuePairs.join(",")}}`;
} }
@ -604,7 +604,7 @@ export function getHandleId(
source: string, source: string,
sourceHandle: string, sourceHandle: string,
target: string, target: string,
targetHandle: string targetHandle: string,
) { ) {
return ( return (
"reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle
@ -615,7 +615,7 @@ export function generateFlow(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[],
name: string name: string,
): generateFlowType { ): generateFlowType {
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } }; const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
const uid = new ShortUniqueId({ length: 5 }); const uid = new ShortUniqueId({ length: 5 });
@ -624,7 +624,7 @@ export function generateFlow(
newFlowData.edges = selection.edges.filter( newFlowData.edges = selection.edges.filter(
(edge) => (edge) =>
selection.nodes.some((node) => node.id === edge.target) && selection.nodes.some((node) => node.id === edge.target) &&
selection.nodes.some((node) => node.id === edge.source) selection.nodes.some((node) => node.id === edge.source),
); );
newFlowData.nodes = selection.nodes; newFlowData.nodes = selection.nodes;
@ -645,7 +645,7 @@ export function generateFlow(
(edge) => (edge) =>
(selection.nodes.some((node) => node.id === edge.target) || (selection.nodes.some((node) => node.id === edge.target) ||
selection.nodes.some((node) => node.id === edge.source)) && selection.nodes.some((node) => node.id === edge.source)) &&
newFlowData.edges.every((e) => e.id !== edge.id) newFlowData.edges.every((e) => e.id !== edge.id),
), ),
}; };
} }
@ -656,13 +656,13 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
const { nodes, edges } = groupNode.data.node!.flow!.data!; const { nodes, edges } = groupNode.data.node!.flow!.data!;
const lastNode = findLastNode(groupNode.data.node!.flow!.data!); const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
newEdges = newEdges.filter( newEdges = newEdges.filter(
(e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id) (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id),
); );
newEdges.forEach((edge) => { newEdges.forEach((edge) => {
if (lastNode && edge.source === lastNode.id) { if (lastNode && edge.source === lastNode.id) {
edge.source = groupNode.id; edge.source = groupNode.id;
let newSourceHandle: sourceHandleType = scapeJSONParse( let newSourceHandle: sourceHandleType = scapeJSONParse(
edge.sourceHandle! edge.sourceHandle!,
); );
newSourceHandle.id = groupNode.id; newSourceHandle.id = groupNode.id;
edge.sourceHandle = scapedJSONStringfy(newSourceHandle); edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
@ -689,7 +689,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
export function filterFlow( export function filterFlow(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
) { ) {
setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node))); setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node)));
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge))); setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
@ -727,7 +727,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) {
export function concatFlows( export function concatFlows(
flow: FlowType, flow: FlowType,
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
) { ) {
const { nodes, edges } = flow.data!; const { nodes, edges } = flow.data!;
setNodes((old) => [...old, ...nodes]); setNodes((old) => [...old, ...nodes]);
@ -736,7 +736,7 @@ export function concatFlows(
export function validateSelection( export function validateSelection(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
edges: Edge[] edges: Edge[],
): Array<string> { ): Array<string> {
const clonedSelection = cloneDeep(selection); const clonedSelection = cloneDeep(selection);
const clonedEdges = cloneDeep(edges); const clonedEdges = cloneDeep(edges);
@ -750,7 +750,7 @@ export function validateSelection(
let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id)); let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id));
// then filter the edges that are connected to the nodes in the set // then filter the edges that are connected to the nodes in the set
let connectedEdges = clonedSelection.edges.filter( let connectedEdges = clonedSelection.edges.filter(
(e) => nodesSet.has(e.source) && nodesSet.has(e.target) (e) => nodesSet.has(e.source) && nodesSet.has(e.target),
); );
// add the edges to the selection // add the edges to the selection
clonedSelection.edges = connectedEdges; clonedSelection.edges = connectedEdges;
@ -764,17 +764,17 @@ export function validateSelection(
clonedSelection.nodes.some( clonedSelection.nodes.some(
(node) => (node) =>
isInputNode(node.data as NodeDataType) || isInputNode(node.data as NodeDataType) ||
isOutputNode(node.data as NodeDataType) isOutputNode(node.data as NodeDataType),
) )
) { ) {
errorsArray.push( errorsArray.push(
"Please select only nodes that are not input or output nodes" "Please select only nodes that are not input or output nodes",
); );
} }
//check if there are two or more nodes with free outputs //check if there are two or more nodes with free outputs
if ( if (
clonedSelection.nodes.filter( clonedSelection.nodes.filter(
(n) => !clonedSelection.edges.some((e) => e.source === n.id) (n) => !clonedSelection.edges.some((e) => e.source === n.id),
).length > 1 ).length > 1
) { ) {
errorsArray.push("Please select only one node with free outputs"); errorsArray.push("Please select only one node with free outputs");
@ -785,7 +785,7 @@ export function validateSelection(
clonedSelection.nodes.some( clonedSelection.nodes.some(
(node) => (node) =>
!clonedSelection.edges.some((edge) => edge.target === node.id) && !clonedSelection.edges.some((edge) => edge.target === node.id) &&
!clonedSelection.edges.some((edge) => edge.source === node.id) !clonedSelection.edges.some((edge) => edge.source === node.id),
) )
) { ) {
errorsArray.push("Please select only nodes that are connected"); errorsArray.push("Please select only nodes that are connected");
@ -842,8 +842,8 @@ export function mergeNodeTemplates({
nodeTemplate[key].display_name nodeTemplate[key].display_name
? nodeTemplate[key].display_name ? nodeTemplate[key].display_name
: nodeTemplate[key].name : nodeTemplate[key].name
? toTitleCase(nodeTemplate[key].name) ? toTitleCase(nodeTemplate[key].name)
: toTitleCase(key); : toTitleCase(key);
} }
} }
}); });
@ -854,7 +854,7 @@ function isHandleConnected(
edges: Edge[], edges: Edge[],
key: string, key: string,
field: TemplateVariableType, field: TemplateVariableType,
nodeId: string nodeId: string,
) { ) {
/* /*
this function receives a flow and a handleId and check if there is a connection with this handle this function receives a flow and a handleId and check if there is a connection with this handle
@ -870,7 +870,7 @@ function isHandleConnected(
id: nodeId, id: nodeId,
proxy: { id: field.proxy!.id, field: field.proxy!.field }, proxy: { id: field.proxy!.id, field: field.proxy!.field },
inputTypes: field.input_types, inputTypes: field.input_types,
} as targetHandleType) } as targetHandleType),
) )
) { ) {
return true; return true;
@ -885,7 +885,7 @@ function isHandleConnected(
fieldName: key, fieldName: key,
id: nodeId, id: nodeId,
inputTypes: field.input_types, inputTypes: field.input_types,
} as targetHandleType) } as targetHandleType),
) )
) { ) {
return true; return true;
@ -908,7 +908,7 @@ export function generateNodeTemplate(Flow: FlowType) {
export function generateNodeFromFlow( export function generateNodeFromFlow(
flow: FlowType, flow: FlowType,
getNodeId: (type: string) => string getNodeId: (type: string) => string,
): NodeType { ): NodeType {
const { nodes } = flow.data!; const { nodes } = flow.data!;
const outputNode = cloneDeep(findLastNode(flow.data!)); const outputNode = cloneDeep(findLastNode(flow.data!));
@ -939,7 +939,7 @@ export function generateNodeFromFlow(
export function connectedInputNodesOnHandle( export function connectedInputNodesOnHandle(
nodeId: string, nodeId: string,
handleId: string, handleId: string,
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] } { nodes, edges }: { nodes: NodeType[]; edges: Edge[] },
) { ) {
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> = const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
[]; [];
@ -976,7 +976,7 @@ export function connectedInputNodesOnHandle(
export function updateProxyIdsOnTemplate( export function updateProxyIdsOnTemplate(
template: APITemplateType, template: APITemplateType,
idsMap: { [key: string]: string } idsMap: { [key: string]: string },
) { ) {
Object.keys(template).forEach((key) => { Object.keys(template).forEach((key) => {
if (template[key].proxy && idsMap[template[key].proxy!.id]) { if (template[key].proxy && idsMap[template[key].proxy!.id]) {
@ -987,7 +987,7 @@ export function updateProxyIdsOnTemplate(
export function updateEdgesIds( export function updateEdgesIds(
edges: Edge[], edges: Edge[],
idsMap: { [key: string]: string } idsMap: { [key: string]: string },
) { ) {
edges.forEach((edge) => { edges.forEach((edge) => {
let targetHandle: targetHandleType = edge.data.targetHandle; let targetHandle: targetHandleType = edge.data.targetHandle;
@ -1019,7 +1019,7 @@ export function expandGroupNode(
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[],
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
) { ) {
const idsMap = updateIds(flow!.data!); const idsMap = updateIds(flow!.data!);
updateProxyIdsOnTemplate(template, idsMap); updateProxyIdsOnTemplate(template, idsMap);
@ -1062,7 +1062,7 @@ export function expandGroupNode(
const lastNode = cloneDeep(findLastNode(flow!.data!)); const lastNode = cloneDeep(findLastNode(flow!.data!));
newEdge.source = lastNode!.id; newEdge.source = lastNode!.id;
let newSourceHandle: sourceHandleType = scapeJSONParse( let newSourceHandle: sourceHandleType = scapeJSONParse(
newEdge.sourceHandle! newEdge.sourceHandle!,
); );
newSourceHandle.id = lastNode!.id; newSourceHandle.id = lastNode!.id;
newEdge.data.sourceHandle = newSourceHandle; newEdge.data.sourceHandle = newSourceHandle;
@ -1119,7 +1119,7 @@ export function expandGroupNode(
export function getGroupStatus( export function getGroupStatus(
flow: FlowType, flow: FlowType,
ssData: { [key: string]: { valid: boolean; params: string } } ssData: { [key: string]: { valid: boolean; params: string } },
) { ) {
let status = { valid: true, params: SUCCESS_BUILD }; let status = { valid: true, params: SUCCESS_BUILD };
const { nodes } = flow.data!; const { nodes } = flow.data!;
@ -1138,7 +1138,7 @@ export function getGroupStatus(
export function createFlowComponent( export function createFlowComponent(
nodeData: NodeDataType, nodeData: NodeDataType,
version: string version: string,
): FlowType { ): FlowType {
const flowNode: FlowType = { const flowNode: FlowType = {
data: { data: {
@ -1174,7 +1174,7 @@ export function downloadNode(NodeFLow: FlowType) {
export function updateComponentNameAndType( export function updateComponentNameAndType(
data: any, data: any,
component: NodeDataType component: NodeDataType,
) {} ) {}
export function removeFileNameFromComponents(flow: FlowType) { export function removeFileNameFromComponents(flow: FlowType) {
@ -1248,7 +1248,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) {
export function downloadFlow( export function downloadFlow(
flow: FlowType, flow: FlowType,
flowName: string, flowName: string,
flowDescription?: string flowDescription?: string,
) { ) {
let clonedFlow = cloneDeep(flow); let clonedFlow = cloneDeep(flow);
removeFileNameFromComponents(clonedFlow); removeFileNameFromComponents(clonedFlow);
@ -1258,7 +1258,7 @@ export function downloadFlow(
...clonedFlow, ...clonedFlow,
name: flowName, name: flowName,
description: flowDescription, description: flowDescription,
}) }),
)}`; )}`;
// create a link element and set its properties // create a link element and set its properties
@ -1273,7 +1273,7 @@ export function downloadFlow(
export function downloadFlows() { export function downloadFlows() {
downloadFlowsFromDatabase().then((flows) => { downloadFlowsFromDatabase().then((flows) => {
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flows) JSON.stringify(flows),
)}`; )}`;
// create a link element and set its properties // create a link element and set its properties
@ -1297,7 +1297,7 @@ export function getRandomDescription(): string {
export const createNewFlow = ( export const createNewFlow = (
flowData: ReactFlowJsonObject, flowData: ReactFlowJsonObject,
flow: FlowType, flow: FlowType,
folderId: string folderId: string,
) => { ) => {
return { return {
description: flow?.description ?? getRandomDescription(), description: flow?.description ?? getRandomDescription(),

View file

@ -21,8 +21,16 @@ export default function cloneFLowWithParent(
} }
export function getInputsAndOutputs(nodes: Node[]) { export function getInputsAndOutputs(nodes: Node[]) {
let inputs: { type: string; id: string; displayName: string }[] = []; let inputs: {
let outputs: { type: string; id: string; displayName: string }[] = []; type: string;
id: string;
displayName: string;
}[] = [];
let outputs: {
type: string;
id: string;
displayName: string;
}[] = [];
nodes.forEach((node) => { nodes.forEach((node) => {
const nodeData: NodeDataType = node.data as NodeDataType; const nodeData: NodeDataType = node.data as NodeDataType;
if (isOutputNode(nodeData)) { if (isOutputNode(nodeData)) {

View file

@ -143,6 +143,8 @@ import {
X, X,
XCircle, XCircle,
Zap, Zap,
RotateCcw,
Settings,
} from "lucide-react"; } from "lucide-react";
import { FaApple, FaDiscord, FaGithub } from "react-icons/fa"; import { FaApple, FaDiscord, FaGithub } from "react-icons/fa";
import { AWSIcon } from "../icons/AWS"; import { AWSIcon } from "../icons/AWS";
@ -526,4 +528,6 @@ export const nodeIconsLucide: iconsType = {
FolderPlusIcon, FolderPlusIcon,
FolderIcon, FolderIcon,
Discord: FaDiscord, Discord: FaDiscord,
RotateCcw,
Settings,
}; };

View file

@ -352,8 +352,9 @@ export function isTimeStampString(str: string): boolean {
export function extractColumnsFromRows( export function extractColumnsFromRows(
rows: object[], rows: object[],
mode: "intersection" | "union", mode: "intersection" | "union",
excludeColumns?: Array<string>,
): (ColDef<any> | ColGroupDef<any>)[] { ): (ColDef<any> | ColGroupDef<any>)[] {
const columnsKeys: { [key: string]: ColDef<any> | ColGroupDef<any> } = {}; let columnsKeys: { [key: string]: ColDef<any> | ColGroupDef<any> } = {};
if (rows.length === 0) { if (rows.length === 0) {
return []; return [];
} }
@ -393,5 +394,11 @@ export function extractColumnsFromRows(
union(); union();
} }
if (excludeColumns) {
for (const key of excludeColumns) {
delete columnsKeys[key];
}
}
return Object.values(columnsKeys); return Object.values(columnsKeys);
} }

View file

@ -24,7 +24,7 @@ test("chat_io_teste", async ({ page }) => {
const jsonContent = readFileSync( const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/ChatTest.json", "src/frontend/tests/end-to-end/assets/ChatTest.json",
"utf-8" "utf-8",
); );
await page.getByTestId("blank-flow").click(); await page.getByTestId("blank-flow").click();
@ -47,7 +47,7 @@ test("chat_io_teste", async ({ page }) => {
"drop", "drop",
{ {
dataTransfer, dataTransfer,
} },
); );
await page.getByLabel("fit view").click(); await page.getByLabel("fit view").click();
await page.getByText("Playground", { exact: true }).click(); await page.getByText("Playground", { exact: true }).click();

View file

@ -57,7 +57,7 @@ test("user must interact with chat with Input/Output", async ({ page }) => {
.getByTestId("textarea-input_value") .getByTestId("textarea-input_value")
.nth(1) .nth(1)
.fill( .fill(
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!" "testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!",
); );
await page.getByTestId("icon-LucideSend").click(); await page.getByTestId("icon-LucideSend").click();
await page.getByText("Close", { exact: true }).click(); await page.getByText("Close", { exact: true }).click();
@ -88,8 +88,8 @@ test("user must interact with chat with Input/Output", async ({ page }) => {
await page await page
.getByText( .getByText(
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!", "testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!",
{ exact: true } { exact: true },
) )
.isVisible() .isVisible(),
); );
}); });

View file

@ -27,7 +27,7 @@ test.describe("drag and drop test", () => {
// Read your file into a buffer. // Read your file into a buffer.
const jsonContent = readFileSync( const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/collection.json", "src/frontend/tests/end-to-end/assets/collection.json",
"utf-8" "utf-8",
); );
// Create the DataTransfer and File // Create the DataTransfer and File
@ -47,7 +47,7 @@ test.describe("drag and drop test", () => {
"drop", "drop",
{ {
dataTransfer, dataTransfer,
} },
); );
const genericNoda = page.getByTestId("div-generic-node"); const genericNoda = page.getByTestId("div-generic-node");

View file

@ -78,32 +78,32 @@ test("dropDownComponent", async ({ page }) => {
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showendpoint_url"]').click(); await page.locator('//*[@id="showendpoint_url"]').click();
expect( expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked() await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showendpoint_url"]').click(); await page.locator('//*[@id="showendpoint_url"]').click();
expect( expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked() await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showregion_name"]').click(); await page.locator('//*[@id="showregion_name"]').click();
expect( expect(
await page.locator('//*[@id="showregion_name"]').isChecked() await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showregion_name"]').click(); await page.locator('//*[@id="showregion_name"]').click();
expect( expect(
await page.locator('//*[@id="showregion_name"]').isChecked() await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showmodel_id // showmodel_id
@ -113,7 +113,7 @@ test("dropDownComponent", async ({ page }) => {
// showmodel_id // showmodel_id
await page.locator('//*[@id="showmodel_id"]').click(); await page.locator('//*[@id="showmodel_id"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_id"]').isChecked() await page.locator('//*[@id="showmodel_id"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showcache"]').click(); await page.locator('//*[@id="showcache"]').click();
@ -124,32 +124,32 @@ test("dropDownComponent", async ({ page }) => {
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showendpoint_url"]').click(); await page.locator('//*[@id="showendpoint_url"]').click();
expect( expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked() await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showendpoint_url"]').click(); await page.locator('//*[@id="showendpoint_url"]').click();
expect( expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked() await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showregion_name"]').click(); await page.locator('//*[@id="showregion_name"]').click();
expect( expect(
await page.locator('//*[@id="showregion_name"]').isChecked() await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showregion_name"]').click(); await page.locator('//*[@id="showregion_name"]').click();
expect( expect(
await page.locator('//*[@id="showregion_name"]').isChecked() await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showmodel_id // showmodel_id
@ -159,7 +159,7 @@ test("dropDownComponent", async ({ page }) => {
// showmodel_id // showmodel_id
await page.locator('//*[@id="showmodel_id"]').click(); await page.locator('//*[@id="showmodel_id"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_id"]').isChecked() await page.locator('//*[@id="showmodel_id"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("dropdown-edit-model_id").click(); await page.getByTestId("dropdown-edit-model_id").click();

View file

@ -40,7 +40,7 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[3]/div/button/div/div' '//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[3]/div/button/div/div',
) )
.hover() .hover()
.then(async () => { .then(async () => {
@ -60,17 +60,17 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page.getByTitle("zoom out").click(); await page.getByTitle("zoom out").click();
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[4]/div/button/div/div' '//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[4]/div/button/div/div',
) )
.hover() .hover()
.then(async () => { .then(async () => {
await expect( await expect(
page.getByTestId("tooltip-Model Specs").first() page.getByTestId("tooltip-Model Specs").first(),
).toBeVisible(); ).toBeVisible();
await page.waitForTimeout(2000); await page.waitForTimeout(2000);
await expect( await expect(
page.getByTestId("tooltip-Model Specs").first() page.getByTestId("tooltip-Model Specs").first(),
).toBeVisible(); ).toBeVisible();
await page.getByTestId("icon-Search").click(); await page.getByTestId("icon-Search").click();
@ -81,12 +81,12 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[5]/div/button/div/div' '//*[@id="react-flow-id"]/div[1]/div[1]/div/div/div[2]/div/div/div[2]/div[5]/div/button/div/div',
) )
.hover() .hover()
.then(async () => { .then(async () => {
await expect( await expect(
page.getByTestId("empty-tooltip-filter").first() page.getByTestId("empty-tooltip-filter").first(),
).toBeVisible(); ).toBeVisible();
}); });
}); });
@ -113,7 +113,7 @@ test("LLMChain - Filter", async ({ page }) => {
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
await page.getByTestId( await page.getByTestId(
"input-list-plus-btn-edit_metadata_indexing_include-2" "input-list-plus-btn-edit_metadata_indexing_include-2",
); );
await page.getByTestId("blank-flow").click(); await page.getByTestId("blank-flow").click();
@ -136,7 +136,7 @@ test("LLMChain - Filter", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[4]/div/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[4]/div/button/div/div',
) )
.click(); .click();
@ -149,14 +149,14 @@ test("LLMChain - Filter", async ({ page }) => {
await expect(page.getByTestId("model_specsChatOpenAI")).toBeVisible(); await expect(page.getByTestId("model_specsChatOpenAI")).toBeVisible();
await expect(page.getByTestId("model_specsChatVertexAI")).toBeVisible(); await expect(page.getByTestId("model_specsChatVertexAI")).toBeVisible();
await expect( await expect(
page.getByTestId("model_specsGoogle Generative AI") page.getByTestId("model_specsGoogle Generative AI"),
).toBeVisible(); ).toBeVisible();
await expect( await expect(
page.getByTestId("model_specsHugging Face Inference API") page.getByTestId("model_specsHugging Face Inference API"),
).toBeVisible(); ).toBeVisible();
await expect(page.getByTestId("model_specsOllama")).toBeVisible(); await expect(page.getByTestId("model_specsOllama")).toBeVisible();
await expect( await expect(
page.getByTestId("model_specsQianfanChatEndpoint") page.getByTestId("model_specsQianfanChatEndpoint"),
).toBeVisible(); ).toBeVisible();
await expect(page.getByTestId("model_specsQianfanLLMEndpoint")).toBeVisible(); await expect(page.getByTestId("model_specsQianfanLLMEndpoint")).toBeVisible();
await expect(page.getByTestId("model_specsVertexAI")).toBeVisible(); await expect(page.getByTestId("model_specsVertexAI")).toBeVisible();
@ -168,7 +168,7 @@ test("LLMChain - Filter", async ({ page }) => {
await expect(page.getByTestId("model_specsAmazon Bedrock")).not.toBeVisible(); await expect(page.getByTestId("model_specsAmazon Bedrock")).not.toBeVisible();
await expect(page.getByTestId("modelsAzure OpenAI")).not.toBeVisible(); await expect(page.getByTestId("modelsAzure OpenAI")).not.toBeVisible();
await expect( await expect(
page.getByTestId("model_specsAzureChatOpenAI") page.getByTestId("model_specsAzureChatOpenAI"),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByTestId("model_specsChatAnthropic")).not.toBeVisible(); await expect(page.getByTestId("model_specsChatAnthropic")).not.toBeVisible();
await expect(page.getByTestId("model_specsChatLiteLLM")).not.toBeVisible(); await expect(page.getByTestId("model_specsChatLiteLLM")).not.toBeVisible();
@ -178,13 +178,13 @@ test("LLMChain - Filter", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[7]/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[7]/button/div/div',
) )
.click(); .click();
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[7]/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div/div/div[2]/div[7]/button/div/div',
) )
.click(); .click();

View file

@ -71,27 +71,27 @@ test("FloatComponent", async ({ page }) => {
await page.getByTestId("showmirostat").click(); await page.getByTestId("showmirostat").click();
expect( expect(
await page.locator('//*[@id="showmirostat"]').isChecked() await page.locator('//*[@id="showmirostat"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("showmirostat_eta").click(); await page.getByTestId("showmirostat_eta").click();
expect( expect(
await page.locator('//*[@id="showmirostat_eta"]').isChecked() await page.locator('//*[@id="showmirostat_eta"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("showmirostat_eta").click(); await page.getByTestId("showmirostat_eta").click();
expect( expect(
await page.locator('//*[@id="showmirostat_eta"]').isChecked() await page.locator('//*[@id="showmirostat_eta"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("showmirostat_tau").click(); await page.getByTestId("showmirostat_tau").click();
expect( expect(
await page.locator('//*[@id="showmirostat_tau"]').isChecked() await page.locator('//*[@id="showmirostat_tau"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("showmirostat_tau").click(); await page.getByTestId("showmirostat_tau").click();
expect( expect(
await page.locator('//*[@id="showmirostat_tau"]').isChecked() await page.locator('//*[@id="showmirostat_tau"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("showmodel").click(); await page.getByTestId("showmodel").click();
@ -114,22 +114,22 @@ test("FloatComponent", async ({ page }) => {
await page.getByTestId("shownum_thread").click(); await page.getByTestId("shownum_thread").click();
expect( expect(
await page.locator('//*[@id="shownum_thread"]').isChecked() await page.locator('//*[@id="shownum_thread"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("shownum_thread").click(); await page.getByTestId("shownum_thread").click();
expect( expect(
await page.locator('//*[@id="shownum_thread"]').isChecked() await page.locator('//*[@id="shownum_thread"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("showrepeat_last_n").click(); await page.getByTestId("showrepeat_last_n").click();
expect( expect(
await page.locator('//*[@id="showrepeat_last_n"]').isChecked() await page.locator('//*[@id="showrepeat_last_n"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("showrepeat_last_n").click(); await page.getByTestId("showrepeat_last_n").click();
expect( expect(
await page.locator('//*[@id="showrepeat_last_n"]').isChecked() await page.locator('//*[@id="showrepeat_last_n"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
@ -145,7 +145,7 @@ test("FloatComponent", async ({ page }) => {
// showtemperature // showtemperature
await page.locator('//*[@id="showtemperature"]').click(); await page.locator('//*[@id="showtemperature"]').click();
expect( expect(
await page.locator('//*[@id="showtemperature"]').isChecked() await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();

View file

@ -29,7 +29,7 @@ test("flowSettings", async ({ page }) => {
await page await page
.getByPlaceholder("Flow name") .getByPlaceholder("Flow name")
.fill( .fill(
"Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test" "Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test",
); );
await page.getByText("Character limit reached").isVisible(); await page.getByText("Character limit reached").isVisible();
@ -41,7 +41,7 @@ test("flowSettings", async ({ page }) => {
await page await page
.getByPlaceholder("Flow description") .getByPlaceholder("Flow description")
.fill( .fill(
"Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test" "Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test Flow Name Test",
); );
await page.getByTestId("save-flow-settings").click(); await page.getByTestId("save-flow-settings").click();

View file

@ -58,7 +58,7 @@ test("add folder by drag and drop", async ({ page }) => {
const jsonContent = readFileSync( const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/collection.json", "src/frontend/tests/end-to-end/assets/collection.json",
"utf-8" "utf-8",
); );
// Create the DataTransfer and File // Create the DataTransfer and File
@ -78,7 +78,7 @@ test("add folder by drag and drop", async ({ page }) => {
"drop", "drop",
{ {
dataTransfer, dataTransfer,
} },
); );
await page.getByText("Getting Started").first().isVisible(); await page.getByText("Getting Started").first().isVisible();

View file

@ -60,69 +60,69 @@ test("InputComponent", async ({ page }) => {
expect( expect(
await page await page
.locator('//*[@id="showchroma_server_cors_allow_origins"]') .locator('//*[@id="showchroma_server_cors_allow_origins"]')
.isChecked() .isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showchroma_server_grpc_port"]').click(); await page.locator('//*[@id="showchroma_server_grpc_port"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked() await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showchroma_server_host"]').click(); await page.locator('//*[@id="showchroma_server_host"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_host"]').isChecked() await page.locator('//*[@id="showchroma_server_host"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showchroma_server_http_port"]').click(); await page.locator('//*[@id="showchroma_server_http_port"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked() await page.locator('//*[@id="showchroma_server_http_port"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click(); await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked() await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showcollection_name"]').click(); await page.locator('//*[@id="showcollection_name"]').click();
expect( expect(
await page.locator('//*[@id="showcollection_name"]').isChecked() await page.locator('//*[@id="showcollection_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showindex_directory"]').click(); await page.locator('//*[@id="showindex_directory"]').click();
expect( expect(
await page.locator('//*[@id="showindex_directory"]').isChecked() await page.locator('//*[@id="showindex_directory"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showchroma_server_cors_allow_origins"]').click(); await page.locator('//*[@id="showchroma_server_cors_allow_origins"]').click();
expect( expect(
await page await page
.locator('//*[@id="showchroma_server_cors_allow_origins"]') .locator('//*[@id="showchroma_server_cors_allow_origins"]')
.isChecked() .isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showchroma_server_grpc_port"]').click(); await page.locator('//*[@id="showchroma_server_grpc_port"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked() await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showchroma_server_host"]').click(); await page.locator('//*[@id="showchroma_server_host"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_host"]').isChecked() await page.locator('//*[@id="showchroma_server_host"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showchroma_server_http_port"]').click(); await page.locator('//*[@id="showchroma_server_http_port"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked() await page.locator('//*[@id="showchroma_server_http_port"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click(); await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click();
expect( expect(
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked() await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showindex_directory"]').click(); await page.locator('//*[@id="showindex_directory"]').click();
expect( expect(
await page.locator('//*[@id="showindex_directory"]').isChecked() await page.locator('//*[@id="showindex_directory"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
let valueEditNode = await page let valueEditNode = await page
@ -152,7 +152,7 @@ test("InputComponent", async ({ page }) => {
await page.locator('//*[@id="showcollection_name"]').click(); await page.locator('//*[@id="showcollection_name"]').click();
expect( expect(
await page.locator('//*[@id="showcollection_name"]').isChecked() await page.locator('//*[@id="showcollection_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();

View file

@ -41,19 +41,19 @@ test("InputListComponent", async ({ page }) => {
await page.getByTestId("edit-button-modal").click(); await page.getByTestId("edit-button-modal").click();
expect( expect(
await page.getByTestId("showmetadata_indexing_exclude").isChecked() await page.getByTestId("showmetadata_indexing_exclude").isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("showmetadata_indexing_exclude").click(); await page.getByTestId("showmetadata_indexing_exclude").click();
expect( expect(
await page.getByTestId("showmetadata_indexing_exclude").isChecked() await page.getByTestId("showmetadata_indexing_exclude").isChecked(),
).toBeTruthy(); ).toBeTruthy();
expect( expect(
await page.getByTestId("showmetadata_indexing_include").isChecked() await page.getByTestId("showmetadata_indexing_include").isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("showmetadata_indexing_include").click(); await page.getByTestId("showmetadata_indexing_include").click();
expect( expect(
await page.getByTestId("showmetadata_indexing_include").isChecked() await page.getByTestId("showmetadata_indexing_include").isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page await page
@ -93,7 +93,7 @@ test("InputListComponent", async ({ page }) => {
.click(); .click();
const plusButtonLocator = page.getByTestId( const plusButtonLocator = page.getByTestId(
"input-list-plus-btn_metadata_indexing_include-1" "input-list-plus-btn_metadata_indexing_include-1",
); );
const elementCount = await plusButtonLocator?.count(); const elementCount = await plusButtonLocator?.count();
@ -164,12 +164,12 @@ test("InputListComponent", async ({ page }) => {
.click(); .click();
const plusButtonLocatorEdit0 = await page.getByTestId( const plusButtonLocatorEdit0 = await page.getByTestId(
"input-list-plus-btn-edit_metadata_indexing_include-0" "input-list-plus-btn-edit_metadata_indexing_include-0",
); );
const elementCountEdit0 = await plusButtonLocatorEdit0?.count(); const elementCountEdit0 = await plusButtonLocatorEdit0?.count();
const plusButtonLocatorEdit2 = await page.getByTestId( const plusButtonLocatorEdit2 = await page.getByTestId(
"input-list-plus-btn-edit_metadata_indexing_include-2" "input-list-plus-btn-edit_metadata_indexing_include-2",
); );
const elementCountEdit2 = await plusButtonLocatorEdit2?.count(); const elementCountEdit2 = await plusButtonLocatorEdit2?.count();
@ -178,13 +178,13 @@ test("InputListComponent", async ({ page }) => {
} }
const minusButtonLocatorEdit1 = await page.getByTestId( const minusButtonLocatorEdit1 = await page.getByTestId(
"input-list-minus-btn-edit_metadata_indexing_include-1" "input-list-minus-btn-edit_metadata_indexing_include-1",
); );
const elementCountMinusEdit1 = await minusButtonLocatorEdit1?.count(); const elementCountMinusEdit1 = await minusButtonLocatorEdit1?.count();
const minusButtonLocatorEdit2 = await page.getByTestId( const minusButtonLocatorEdit2 = await page.getByTestId(
"input-list-minus-btn-edit_metadata_indexing_include-2" "input-list-minus-btn-edit_metadata_indexing_include-2",
); );
const elementCountMinusEdit2 = await minusButtonLocatorEdit2?.count(); const elementCountMinusEdit2 = await minusButtonLocatorEdit2?.count();

View file

@ -87,77 +87,77 @@ test("IntComponent", async ({ page }) => {
await page.locator('//*[@id="showmodel_kwargs"]').click(); await page.locator('//*[@id="showmodel_kwargs"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_kwargs"]').isChecked() await page.locator('//*[@id="showmodel_kwargs"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showmodel_name"]').click(); await page.locator('//*[@id="showmodel_name"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_name"]').isChecked() await page.locator('//*[@id="showmodel_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showopenai_api_base"]').click(); await page.locator('//*[@id="showopenai_api_base"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_base"]').isChecked() await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showopenai_api_key"]').click(); await page.locator('//*[@id="showopenai_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked() await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showtemperature"]').click(); await page.locator('//*[@id="showtemperature"]').click();
expect( expect(
await page.locator('//*[@id="showtemperature"]').isChecked() await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showmodel_kwargs"]').click(); await page.locator('//*[@id="showmodel_kwargs"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_kwargs"]').isChecked() await page.locator('//*[@id="showmodel_kwargs"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showmodel_name"]').click(); await page.locator('//*[@id="showmodel_name"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_name"]').isChecked() await page.locator('//*[@id="showmodel_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showopenai_api_base"]').click(); await page.locator('//*[@id="showopenai_api_base"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_base"]').isChecked() await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showopenai_api_key"]').click(); await page.locator('//*[@id="showopenai_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked() await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showtemperature"]').click(); await page.locator('//*[@id="showtemperature"]').click();
expect( expect(
await page.locator('//*[@id="showtemperature"]').isChecked() await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showmodel_kwargs"]').click(); await page.locator('//*[@id="showmodel_kwargs"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_kwargs"]').isChecked() await page.locator('//*[@id="showmodel_kwargs"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showmodel_name"]').click(); await page.locator('//*[@id="showmodel_name"]').click();
expect( expect(
await page.locator('//*[@id="showmodel_name"]').isChecked() await page.locator('//*[@id="showmodel_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showopenai_api_base"]').click(); await page.locator('//*[@id="showopenai_api_base"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_base"]').isChecked() await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showopenai_api_key"]').click(); await page.locator('//*[@id="showopenai_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked() await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showtemperature"]').click(); await page.locator('//*[@id="showtemperature"]').click();
expect( expect(
await page.locator('//*[@id="showtemperature"]').isChecked() await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
@ -172,7 +172,7 @@ test("IntComponent", async ({ page }) => {
await page.locator('//*[@id="showtimeout"]').click(); await page.locator('//*[@id="showtimeout"]').click();
expect( expect(
await page.locator('//*[@id="showtimeout"]').isChecked() await page.locator('//*[@id="showtimeout"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
const valueEditNode = await page const valueEditNode = await page

View file

@ -81,7 +81,7 @@ test("KeypairListComponent", async ({ page }) => {
expect(await page.locator('//*[@id="showcache"]').isChecked()).toBeFalsy(); expect(await page.locator('//*[@id="showcache"]').isChecked()).toBeFalsy();
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
@ -96,7 +96,7 @@ test("KeypairListComponent", async ({ page }) => {
await page.locator('//*[@id="showcredentials_profile_name"]').click(); await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect( expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked() await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showcache"]').click(); await page.locator('//*[@id="showcache"]').click();
expect(await page.locator('//*[@id="showcache"]').isChecked()).toBeTruthy(); expect(await page.locator('//*[@id="showcache"]').isChecked()).toBeTruthy();

View file

@ -61,7 +61,7 @@ test("LangflowShortcuts", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div[1]/div[1]/div[1]/div/div[2]/div[2]/div/div[1]/div/div[1]/div/div/div[1]' '//*[@id="react-flow-id"]/div[1]/div[1]/div[1]/div/div[2]/div[2]/div/div[1]/div/div[1]/div/div/div[1]',
) )
.click(); .click();
await page.keyboard.press("Backspace"); await page.keyboard.press("Backspace");
@ -84,7 +84,7 @@ test("LangflowShortcuts", async ({ page }) => {
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div[1]/div[1]/div[1]/div/div[2]/div[2]/div/div[1]/div/div[1]/div/div/div[1]' '//*[@id="react-flow-id"]/div[1]/div[1]/div[1]/div/div[2]/div[2]/div/div[1]/div/div[1]/div/div/div[1]',
) )
.click(); .click();
await page.keyboard.press("Backspace"); await page.keyboard.press("Backspace");

View file

@ -41,7 +41,7 @@ test("NestedComponent", async ({ page }) => {
await page.locator('//*[@id="showpool_threads"]').click(); await page.locator('//*[@id="showpool_threads"]').click();
expect( expect(
await page.locator('//*[@id="showpool_threads"]').isChecked() await page.locator('//*[@id="showpool_threads"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
//showtext_key //showtext_key
@ -53,140 +53,140 @@ test("NestedComponent", async ({ page }) => {
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showindex_name // showindex_name
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showindex_name // showindex_name
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showindex_name // showindex_name
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showindex_name // showindex_name
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
// showindex_name // showindex_name
await page.locator('//*[@id="showindex_name"]').click(); await page.locator('//*[@id="showindex_name"]').click();
expect( expect(
await page.locator('//*[@id="showindex_name"]').isChecked() await page.locator('//*[@id="showindex_name"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// shownamespace // shownamespace
await page.locator('//*[@id="shownamespace"]').click(); await page.locator('//*[@id="shownamespace"]').click();
expect( expect(
await page.locator('//*[@id="shownamespace"]').isChecked() await page.locator('//*[@id="shownamespace"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
// showpinecone_api_key // showpinecone_api_key
await page.locator('//*[@id="showpinecone_api_key"]').click(); await page.locator('//*[@id="showpinecone_api_key"]').click();
expect( expect(
await page.locator('//*[@id="showpinecone_api_key"]').isChecked() await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
//showpool_threads //showpool_threads
await page.locator('//*[@id="showpool_threads"]').click(); await page.locator('//*[@id="showpool_threads"]').click();
expect( expect(
await page.locator('//*[@id="showpool_threads"]').isChecked() await page.locator('//*[@id="showpool_threads"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
//showtext_key //showtext_key
await page.locator('//*[@id="showtext_key"]').click(); await page.locator('//*[@id="showtext_key"]').click();
expect( expect(
await page.locator('//*[@id="showtext_key"]').isChecked() await page.locator('//*[@id="showtext_key"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();

View file

@ -138,7 +138,7 @@ test("PromptTemplateComponent", async ({ page }) => {
await page.locator('//*[@id="showtemplate"]').click(); await page.locator('//*[@id="showtemplate"]').click();
expect( expect(
await page.locator('//*[@id="showtemplate"]').isChecked() await page.locator('//*[@id="showtemplate"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showprompt"]').click(); await page.locator('//*[@id="showprompt"]').click();
@ -158,7 +158,7 @@ test("PromptTemplateComponent", async ({ page }) => {
await page.locator('//*[@id="showtemplate"]').click(); await page.locator('//*[@id="showtemplate"]').click();
expect( expect(
await page.locator('//*[@id="showtemplate"]').isChecked() await page.locator('//*[@id="showtemplate"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showprompt"]').click(); await page.locator('//*[@id="showprompt"]').click();

View file

@ -27,7 +27,7 @@ test.describe("save component tests", () => {
// Read your file into a buffer. // Read your file into a buffer.
const jsonContent = readFileSync( const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/flow_group_test.json", "src/frontend/tests/end-to-end/assets/flow_group_test.json",
"utf-8" "utf-8",
); );
// Create the DataTransfer and File // Create the DataTransfer and File
@ -49,7 +49,7 @@ test.describe("save component tests", () => {
"drop", "drop",
{ {
dataTransfer, dataTransfer,
} },
); );
const genericNoda = page.getByTestId("div-generic-node"); const genericNoda = page.getByTestId("div-generic-node");

View file

@ -262,7 +262,7 @@ test("should share component with share button", async ({ page }) => {
await page.getByText("Set workflow status to public").isVisible(); await page.getByText("Set workflow status to public").isVisible();
await page await page
.getByText( .getByText(
"Attention: API keys in specified fields are automatically removed upon sharing." "Attention: API keys in specified fields are automatically removed upon sharing.",
) )
.isVisible(); .isVisible();
await page.getByText("Export").first().isVisible(); await page.getByText("Export").first().isVisible();

View file

@ -60,7 +60,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Click and hold on the first element // Click and hold on the first element
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[1]/div/div[2]/div[6]/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[1]/div/div[2]/div[6]/button/div/div',
) )
.hover(); .hover();
await page.mouse.down(); await page.mouse.down();
@ -68,7 +68,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Move to the second element // Move to the second element
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[9]/div/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[9]/div/button/div/div',
) )
.hover(); .hover();
@ -92,7 +92,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Click and hold on the first element // Click and hold on the first element
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[13]/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[13]/button/div/div',
) )
.hover(); .hover();
await page.mouse.down(); await page.mouse.down();
@ -100,7 +100,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Move to the second element // Move to the second element
await page await page
.locator( .locator(
'//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[3]/div/div[2]/div[3]/div/button/div/div' '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[3]/div/div[2]/div[3]/div/button/div/div',
) )
.hover(); .hover();

View file

@ -45,7 +45,7 @@ test("ToggleComponent", async ({ page }) => {
await page.locator('//*[@id="showload_hidden"]').click(); await page.locator('//*[@id="showload_hidden"]').click();
expect( expect(
await page.locator('//*[@id="showload_hidden"]').isChecked() await page.locator('//*[@id="showload_hidden"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
@ -81,12 +81,12 @@ test("ToggleComponent", async ({ page }) => {
await page.locator('//*[@id="showload_hidden"]').click(); await page.locator('//*[@id="showload_hidden"]').click();
expect( expect(
await page.locator('//*[@id="showload_hidden"]').isChecked() await page.locator('//*[@id="showload_hidden"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showmax_concurrency"]').click(); await page.locator('//*[@id="showmax_concurrency"]').click();
expect( expect(
await page.locator('//*[@id="showmax_concurrency"]').isChecked() await page.locator('//*[@id="showmax_concurrency"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showpath"]').click(); await page.locator('//*[@id="showpath"]').click();
@ -94,22 +94,22 @@ test("ToggleComponent", async ({ page }) => {
await page.locator('//*[@id="showrecursive"]').click(); await page.locator('//*[@id="showrecursive"]').click();
expect( expect(
await page.locator('//*[@id="showrecursive"]').isChecked() await page.locator('//*[@id="showrecursive"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showsilent_errors"]').click(); await page.locator('//*[@id="showsilent_errors"]').click();
expect( expect(
await page.locator('//*[@id="showsilent_errors"]').isChecked() await page.locator('//*[@id="showsilent_errors"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showuse_multithreading"]').click(); await page.locator('//*[@id="showuse_multithreading"]').click();
expect( expect(
await page.locator('//*[@id="showuse_multithreading"]').isChecked() await page.locator('//*[@id="showuse_multithreading"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.locator('//*[@id="showmax_concurrency"]').click(); await page.locator('//*[@id="showmax_concurrency"]').click();
expect( expect(
await page.locator('//*[@id="showmax_concurrency"]').isChecked() await page.locator('//*[@id="showmax_concurrency"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showpath"]').click(); await page.locator('//*[@id="showpath"]').click();
@ -117,17 +117,17 @@ test("ToggleComponent", async ({ page }) => {
await page.locator('//*[@id="showrecursive"]').click(); await page.locator('//*[@id="showrecursive"]').click();
expect( expect(
await page.locator('//*[@id="showrecursive"]').isChecked() await page.locator('//*[@id="showrecursive"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showsilent_errors"]').click(); await page.locator('//*[@id="showsilent_errors"]').click();
expect( expect(
await page.locator('//*[@id="showsilent_errors"]').isChecked() await page.locator('//*[@id="showsilent_errors"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.locator('//*[@id="showuse_multithreading"]').click(); await page.locator('//*[@id="showuse_multithreading"]').click();
expect( expect(
await page.locator('//*[@id="showuse_multithreading"]').isChecked() await page.locator('//*[@id="showuse_multithreading"]').isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
@ -144,38 +144,38 @@ test("ToggleComponent", async ({ page }) => {
await page.locator('//*[@id="showload_hidden"]').click(); await page.locator('//*[@id="showload_hidden"]').click();
expect( expect(
await page.locator('//*[@id="showload_hidden"]').isChecked() await page.locator('//*[@id="showload_hidden"]').isChecked(),
).toBeTruthy(); ).toBeTruthy();
expect( expect(
await page.getByTestId("toggle-edit-load_hidden").isChecked() await page.getByTestId("toggle-edit-load_hidden").isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByText("Save Changes", { exact: true }).click(); await page.getByText("Save Changes", { exact: true }).click();
await page.getByTestId("toggle-load_hidden").click(); await page.getByTestId("toggle-load_hidden").click();
expect( expect(
await page.getByTestId("toggle-load_hidden").isChecked() await page.getByTestId("toggle-load_hidden").isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("toggle-load_hidden").click(); await page.getByTestId("toggle-load_hidden").click();
expect( expect(
await page.getByTestId("toggle-load_hidden").isChecked() await page.getByTestId("toggle-load_hidden").isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("toggle-load_hidden").click(); await page.getByTestId("toggle-load_hidden").click();
expect( expect(
await page.getByTestId("toggle-load_hidden").isChecked() await page.getByTestId("toggle-load_hidden").isChecked(),
).toBeFalsy(); ).toBeFalsy();
await page.getByTestId("toggle-load_hidden").click(); await page.getByTestId("toggle-load_hidden").click();
expect( expect(
await page.getByTestId("toggle-load_hidden").isChecked() await page.getByTestId("toggle-load_hidden").isChecked(),
).toBeTruthy(); ).toBeTruthy();
await page.getByTestId("toggle-load_hidden").click(); await page.getByTestId("toggle-load_hidden").click();
expect( expect(
await page.getByTestId("toggle-load_hidden").isChecked() await page.getByTestId("toggle-load_hidden").isChecked(),
).toBeFalsy(); ).toBeFalsy();
} }
}); });