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!")
```
# 部署
## 在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。
@ -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.
- 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
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.
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.
3. Paste your OpenAI API Key (`sk-...`) in the **Value** field.
4. Select **Credential** for the **Type**.
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**.
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.
3. Paste your OpenAI API Key (`sk-...`) in the **Value** field.
4. Select **Credential** for the **Type**.
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.
Subsequently, clicking the 🌐 button in a Text field will display the new variable in the dropdown.
<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>
<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.
<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>
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";
# Inputs and Outputs
@ -29,9 +29,8 @@ This component collects user input from the chat.
<Admonition type="note" title="Note">
<p>
If `As Record` is `true` and the `Message` is a `Record`, the data
of the `Record` will be updated with the `Sender`, `Sender Name`, and
`Session ID`.
If `As Record` is `true` and the `Message` is a `Record`, the data of the
`Record` will be updated with the `Sender`, `Sender Name`, and `Session ID`.
</p>
</Admonition>
@ -112,9 +111,10 @@ This component sends a message to the chat.
- **Message:** Specifies the text of the message.
<Admonition type="note" title="Note">
<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`.
</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`.
</p>
</Admonition>
### 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.
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
@ -155,7 +154,8 @@ The `PromptTemplate` component enables users to create prompts and define variab
<Admonition type="info">
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>
- **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`.
`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.

798
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,9 +1,10 @@
from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query
from langflow.services.deps import get_monitor_service
from langflow.services.monitor.schema import (
MessageModelRequest,
MessageModelResponse,
TransactionModelResponse,
VertexBuildMapModel,
@ -66,6 +67,44 @@ async def get_messages(
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])
async def get_transactions(
source: Optional[str] = Query(None),

View file

@ -122,6 +122,13 @@ class MessageModelResponse(MessageModel):
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):
index: Optional[int] = Field(default=None, alias="index", exclude=True)
id: Optional[str] = Field(default=None, alias="id")

View file

@ -32,6 +32,10 @@ class MonitorService(Service):
except Exception as 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):
return self.load_table_as_dataframe(table_name)
@ -69,7 +73,7 @@ class MonitorService(Service):
valid: Optional[bool] = None,
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 = []
if 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:
df = conn.execute(query).df()
print(query)
return df.to_dict(orient="records")
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:
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}'"
with duckdb.connect(str(self.db_path)) as conn:
conn.execute(query)
return self.exec_query(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):
self.add_row("messages", message)

View file

@ -26,6 +26,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0",
"@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": {
"version": "1.0.7",
"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-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0",
"@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 componentFields = useTypesStore((state) => state.ComponentFields);
const unavaliableFields = new Set(
Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields))
Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)),
);
const availableFields = () => {
const fields = Array.from(componentFields).filter(
(field) => !unavaliableFields.has(field)
(field) => !unavaliableFields.has(field),
);
return sortByName(fields);
};
const addGlobalVariable = useGlobalVariablesStore(
(state) => state.addGlobalVariable
(state) => state.addGlobalVariable,
);
function handleSaveVariable() {

View file

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

View file

@ -33,7 +33,7 @@ const SideBarFoldersButtonsComponent = ({
const [foldersNames, setFoldersNames] = useState({});
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
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 currentFolder = pathname.split("/");
@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({
const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop(
folderId,
handleFolderChange
handleFolderChange,
);
const handleUploadFlowsToFolder = () => {
@ -73,7 +73,7 @@ const SideBarFoldersButtonsComponent = ({
addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => {
getFoldersApi(true);
}
},
);
}
@ -119,7 +119,7 @@ const SideBarFoldersButtonsComponent = ({
<>
{folders.map((item, index) => {
const editFolderName = editFolders?.filter(
(folder) => folder.name === item.name
(folder) => folder.name === item.name,
)[0];
return (
<div
@ -135,7 +135,7 @@ const SideBarFoldersButtonsComponent = ({
? "border border-border bg-muted hover:bg-muted"
: "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",
folderIdDragging === item.id! ? "bg-border" : ""
folderIdDragging === item.id! ? "bg-border" : "",
)}
onClick={() => handleChangeFolder!(item.id!)}
>
@ -205,7 +205,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
}))
})),
);
}
if (e.key === "Enter") {
@ -238,10 +238,10 @@ const SideBarFoldersButtonsComponent = ({
};
const updatedFolder = await updateFolder(
body,
item.id!
item.id!,
);
const updateFolders = folders.filter(
(f) => f.name !== item.name
(f) => f.name !== item.name,
);
setFolders([...updateFolders, updatedFolder]);
setFoldersNames({});
@ -249,7 +249,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
}))
})),
);
} else {
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-theme-quartz.css"; // Optional Theme applied to the grid
import { AgGridReact, AgGridReactProps } from "ag-grid-react";
import { ElementRef, forwardRef, useCallback } from "react";
import { ElementRef, forwardRef, useEffect, useRef } from "react";
import {
DEFAULT_TABLE_ALERT_MSG,
DEFAULT_TABLE_ALERT_TITLE,
} from "../../constants/constants";
import { useDarkStore } from "../../stores/darkStore";
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 { 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 {
columnDefs: NonNullable<AgGridReactProps["columnDefs"]>;
rowData: NonNullable<AgGridReactProps["rowData"]>;
alertTitle?: string;
alertDescription?: string;
editable?: boolean | string[];
}
const TableComponent = forwardRef<
@ -31,7 +36,67 @@ const TableComponent = forwardRef<
},
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 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) {
return (
<div className="flex h-full w-full items-center justify-center rounded-md border">
@ -46,12 +111,12 @@ const TableComponent = forwardRef<
</div>
);
}
return (
<div
className={cn(
dark ? "ag-theme-quartz-dark" : "ag-theme-quartz",
"ag-theme-shadcn flex h-full flex-col",
"relative",
)} // applying the grid theme
>
<AgGridReact
@ -60,8 +125,13 @@ const TableComponent = forwardRef<
defaultColDef={{
minWidth: 100,
}}
ref={ref}
columnDefs={colDef}
ref={realRef}
pagination={true}
onGridReady={onGridReady}
onColumnMoved={onColumnMoved}
/>
<ResetColumns resetGrid={() => resetGrid(realRef, initialColumnDefs)} />
</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);
return Promise.reject(error);
}
},
);
const isAuthorizedURL = (url) => {
@ -65,10 +65,10 @@ function ApiInterceptor() {
const parsedURL = new URL(url);
const isDomainAllowed = authorizedDomains.some(
(domain) => parsedURL.origin === new URL(domain).origin
(domain) => parsedURL.origin === new URL(domain).origin,
);
const isEndpointAllowed = authorizedEndpoints.some((endpoint) =>
parsedURL.pathname.includes(endpoint)
parsedURL.pathname.includes(endpoint),
);
return isDomainAllowed || isEndpointAllowed;
@ -96,7 +96,7 @@ function ApiInterceptor() {
},
(error) => {
return Promise.reject(error);
}
},
);
return () => {
@ -128,7 +128,7 @@ function ApiInterceptor() {
if (error?.config?.headers) {
delete error.config.headers["Authorization"];
error.config.headers["Authorization"] = `Bearer ${cookies.get(
"access_token_lf"
"access_token_lf",
)}`;
const response = await axios.request(error.config);
return response;

View file

@ -28,6 +28,7 @@ import {
UploadFileTypeAPI,
errorsTypeAPI,
} from "./../../types/api/index";
import { Message } from "../../types/messages";
/**
* Fetches all objects from the API endpoint.
@ -61,7 +62,7 @@ export async function sendAll(data: sendAllProps) {
}
export async function postValidateCode(
code: string
code: string,
): Promise<AxiosResponse<errorsTypeAPI>> {
return await api.post(`${BASE_URL_API}validate/code`, { code });
}
@ -76,7 +77,7 @@ export async function postValidateCode(
export async function postValidatePrompt(
name: string,
template: string,
frontend_node: APIClassType
frontend_node: APIClassType,
): Promise<AxiosResponse<PromptTypeAPI>> {
return api.post(`${BASE_URL_API}validate/prompt`, {
name,
@ -149,7 +150,7 @@ export async function saveFlowToDatabase(newFlow: {
* @throws Will throw an error if the update fails.
*/
export async function updateFlowInDatabase(
updatedFlow: FlowType
updatedFlow: FlowType,
): Promise<FlowType> {
try {
const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, {
@ -327,7 +328,7 @@ export async function getHealth() {
*
*/
export async function getBuildStatus(
flowId: string
flowId: string,
): Promise<AxiosResponse<BuildStatusTypeAPI>> {
return await api.get(`${BASE_URL_API}build/${flowId}/status`);
}
@ -340,7 +341,7 @@ export async function getBuildStatus(
*
*/
export async function postBuildInit(
flow: FlowType
flow: FlowType,
): Promise<AxiosResponse<InitTypeAPI>> {
return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow);
}
@ -356,7 +357,7 @@ export async function postBuildInit(
*/
export async function uploadFile(
file: File,
id: string
id: string,
): Promise<AxiosResponse<UploadFileTypeAPI>> {
const formData = new FormData();
formData.append("file", file);
@ -365,7 +366,7 @@ export async function uploadFile(
export async function postCustomComponent(
code: string,
apiClass: APIClassType
apiClass: APIClassType,
): Promise<AxiosResponse<APIClassType>> {
// let template = apiClass.template;
return await api.post(`${BASE_URL_API}custom_component`, {
@ -378,7 +379,7 @@ export async function postCustomComponentUpdate(
code: string,
template: APITemplateType,
field: string,
field_value: any
field_value: any,
): Promise<AxiosResponse<APIClassType>> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
@ -400,7 +401,7 @@ export async function onLogin(user: LoginType) {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
},
);
if (response.status === 200) {
@ -462,11 +463,11 @@ export async function addUser(user: UserInputType): Promise<Array<Users>> {
export async function getUsersPage(
skip: number,
limit: number
limit: number,
): Promise<Array<Users>> {
try {
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) {
return res.data;
@ -503,7 +504,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) {
try {
const res = await api.patch(
`${BASE_URL_API}users/${user_id}/reset-password`,
user
user,
);
if (res.status === 200) {
return res.data;
@ -577,7 +578,7 @@ export async function saveFlowStore(
last_tested_version?: string;
},
tags: string[],
publicFlow = false
publicFlow = false,
): Promise<FlowType> {
try {
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) {
try {
const res = await api.get(
`${BASE_URL_API}store/components/${component_id}`
`${BASE_URL_API}store/components/${component_id}`,
);
if (res.status === 200) {
return res.data;
@ -721,7 +722,7 @@ export async function searchComponent(
page?: number | null,
limit?: number | null,
status?: string | null,
tags?: string[]
tags?: string[],
): Promise<StoreComponentResponse | undefined> {
try {
let url = `${BASE_URL_API}store/components/`;
@ -833,7 +834,7 @@ export async function updateFlowStore(
},
tags: string[],
publicFlow = false,
id: string
id: string,
): Promise<FlowType> {
try {
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(
name: string,
value: string,
id: string
id: string,
) {
try {
const response = api.patch(`${BASE_URL_API}variables/${id}`, {
@ -936,7 +937,7 @@ export async function getVerticesOrder(
startNodeId?: string | null,
stopNodeId?: string | null,
nodes?: Node[],
Edges?: Edge[]
Edges?: Edge[],
): Promise<AxiosResponse<VerticesOrderTypeAPI>> {
// nodeId is optional and is a query parameter
// if nodeId is not provided, the API will return all vertices
@ -956,19 +957,19 @@ export async function getVerticesOrder(
return await api.post(
`${BASE_URL_API}build/${flowId}/vertices`,
data,
config
config,
);
}
export async function postBuildVertex(
flowId: string,
vertexId: string,
input_value: string
input_value: string,
): Promise<AxiosResponse<VertexBuildTypeAPI>> {
// input_value is optional and is a query parameter
return await api.post(
`${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(
flowId: string
flowId: string,
): Promise<AxiosResponse<any>> {
const config = {};
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.
*/
export async function multipleDeleteFlowsComponents(
flowIds: string[]
flowIds: string[],
): Promise<AxiosResponse<any>[]> {
const batches: string[][] = [];
@ -1029,7 +1030,7 @@ export async function multipleDeleteFlowsComponents(
// Execute all delete requests
const responses: Promise<AxiosResponse<any>>[] = batches.map((batch) =>
deleteBatch(batch)
deleteBatch(batch),
);
// Return the responses after all requests are completed
@ -1039,7 +1040,7 @@ export async function multipleDeleteFlowsComponents(
export async function getTransactionTable(
id: string,
mode: "intersection" | "union",
params = {}
params = {},
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> {
const config = {};
config["params"] = { flow_id: id };
@ -1052,16 +1053,47 @@ export async function getTransactionTable(
}
export async function getMessagesTable(
id: string,
mode: "intersection" | "union",
params = {}
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> {
id?: string,
excludedFields?: string[],
params = {},
): Promise<{ rows: Array<Message>; columns: Array<ColDef | ColGroupDef> }> {
const config = {};
config["params"] = { flow_id: id };
if (id) {
config["params"] = { flow_id: id };
}
if (params) {
config["params"] = { ...config["params"], ...params };
}
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 };
}
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 [inputDescription, setInputDescription] = useState(false);
const [nodeDescription, setNodeDescription] = useState(
data.node?.description!
data.node?.description!,
);
const [isOutdated, setIsOutdated] = useState(false);
const buildStatus = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.status
(state) => state.flowBuildStatus[data.id]?.status,
);
const lastRunTime = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.timestamp
(state) => state.flowBuildStatus[data.id]?.timestamp,
);
const [validationStatus, setValidationStatus] =
useState<validationStatusType | null>(null);
@ -115,7 +115,7 @@ export default function GenericNode({
updateNodeInternals(data.id);
},
[data.id, data.node, setNode, setIsOutdated]
[data.id, data.node, setNode, setIsOutdated],
);
if (!data.node!.template) {
@ -255,7 +255,7 @@ export default function GenericNode({
const isDark = useDarkStore((state) => state.dark);
const renderIconStatus = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
validationStatus: validationStatusType | null,
) => {
if (buildStatus === BuildStatus.BUILDING) {
return <Loading className="text-medium-indigo" />;
@ -296,7 +296,7 @@ export default function GenericNode({
};
const getSpecificClassFromBuildStatus = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
validationStatus: validationStatusType | null,
) => {
let isInvalid = validationStatus && !validationStatus.valid;
@ -320,11 +320,11 @@ export default function GenericNode({
selected: boolean,
showNode: boolean,
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
validationStatus: validationStatusType | null,
) => {
const specificClassFromBuildStatus = getSpecificClassFromBuildStatus(
buildStatus,
validationStatus
validationStatus,
);
const baseBorderClass = getBaseBorderClass(selected);
@ -333,7 +333,7 @@ export default function GenericNode({
baseBorderClass,
nodeSizeClass,
"generic-node-div",
specificClassFromBuildStatus
specificClassFromBuildStatus,
);
return names;
};
@ -393,7 +393,7 @@ export default function GenericNode({
selected,
showNode,
buildStatus,
validationStatus
validationStatus,
)}
>
{data.node?.beta && showNode && (
@ -524,7 +524,7 @@ export default function GenericNode({
}
title={getFieldTitle(
data.node?.template!,
templateField
templateField,
)}
info={data.node?.template[templateField].info}
name={templateField}
@ -552,7 +552,7 @@ export default function GenericNode({
proxy={data.node?.template[templateField].proxy}
showNode={showNode}
/>
)
),
)}
<ParameterComponent
key={scapedJSONStringfy({
@ -709,7 +709,7 @@ export default function GenericNode({
!data.node?.description) &&
nameEditable
? "font-light italic"
: ""
: "",
)}
onClick={(e) => {
setInputDescription(true);
@ -771,13 +771,13 @@ export default function GenericNode({
}
title={getFieldTitle(
data.node?.template!,
templateField
templateField,
)}
info={data.node?.template[templateField].info}
name={templateField}
tooltipTitle={
data.node?.template[templateField].input_types?.join(
"\n"
"\n",
) ?? data.node?.template[templateField].type
}
required={data.node!.template[templateField].required}
@ -804,7 +804,7 @@ export default function GenericNode({
<div
className={classNames(
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,
setNode,
renderTooltips,
setIsLoading
setIsLoading,
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);

View file

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

View file

@ -1,5 +1,11 @@
import { useEffect, useRef, useState } from "react";
import IconComponent from "../../../../components/genericIconComponent";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from "../../../../components/ui/select";
import {
CHAT_FIRST_INITIAL_TEXT,
CHAT_SECOND_INITIAL_TEXT,
@ -118,10 +124,21 @@ export default function ChatView({
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(
chat: ChatMessageType,
message: string,
stream_url?: string
stream_url?: string,
) {
// if (message === "") return;
chat.message = message;
@ -149,18 +166,57 @@ export default function ChatView({
<div className="eraser-column-arrangement">
<div className="eraser-size">
<div className="eraser-position">
<button disabled={lockChat} onClick={() => clearChat()}>
<button
className="flex gap-1"
onClick={() => handleSelectChange("builds")}
>
<IconComponent
name="Eraser"
className={classNames(
"h-5 w-5",
lockChat
? "animate-pulse text-primary"
: "text-primary hover:text-gray-600"
"h-5 w-5 transition-all duration-100",
lockChat ? "animate-pulse text-primary" : "text-primary",
)}
aria-hidden="true"
/>
</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 ref={messagesRef} className="chat-message-div">
{chatHistory?.length > 0 ? (

View file

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

View file

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

View file

@ -35,7 +35,7 @@ const ApiModal = forwardRef(
flow: FlowType;
children: ReactNode;
},
ref
ref,
) => {
const tweak = useTweaksStore((state) => state.tweak);
const addTweaks = useTweaksStore((state) => state.setTweak);
@ -50,18 +50,18 @@ const ApiModal = forwardRef(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name
flow?.endpoint_name,
);
const curl_run_code = getCurlRunCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name
flow?.endpoint_name,
);
const curl_webhook_code = getCurlWebhookCode(
flow?.id,
autoLogin,
flow?.endpoint_name
flow?.endpoint_name,
);
const pythonCode = getPythonCode(flow?.name, tweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
@ -77,7 +77,7 @@ const ApiModal = forwardRef(
pythonCode,
];
const [tabs, setTabs] = useState(
createTabsArray(codesArray, includeWebhook)
createTabsArray(codesArray, includeWebhook),
);
const canShowTweaks =
@ -126,7 +126,7 @@ const ApiModal = forwardRef(
buildTweakObject(
nodeId,
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(
tw: string,
changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType
template: TemplateVariableType,
) {
changes = getChangesType(changes, template);
@ -185,7 +185,7 @@ const ApiModal = forwardRef(
flow?.id,
autoLogin,
cloneTweak,
flow?.endpoint_name
flow?.endpoint_name,
);
const pythonCode = getPythonCode(flow?.name, cloneTweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
@ -229,7 +229,7 @@ const ApiModal = forwardRef(
</BaseModal.Content>
</BaseModal>
);
}
},
);
export default ApiModal;

View file

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

View file

@ -33,11 +33,13 @@ export default function FlowLogsModal({
setRows(rows);
});
} else if (activeTab === "Messages") {
getMessagesTable(currentFlowId, "union").then((data) => {
const { columns, rows } = data;
setColumns(columns.map((col) => ({ ...col, editable: true })));
setRows(rows);
});
getMessagesTable("union", currentFlowId, ["index", "flow_id"]).then(
(data) => {
const { columns, rows } = data;
setColumns(columns.map((col) => ({ ...col, editable: true })));
setRows(rows);
},
);
}
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 === "int" ||
data.node.template[templateField].type === "dict" ||
data.node.template[templateField].type === "NestedDict")
data.node.template[templateField].type === "NestedDict"),
).length;
const templates = useTypesStore((state) => state.templates);
const hasStore = useStoreStore((state) => state.hasStore);
@ -85,7 +85,7 @@ export default function NodeToolbarComponent({
const [showconfirmShare, setShowconfirmShare] = useState(false);
const [showOverrideModal, setShowOverrideModal] = useState(false);
const [flowComponent, setFlowComponent] = useState<FlowType>(
createFlowComponent(cloneDeep(data), version)
createFlowComponent(cloneDeep(data), version),
);
const openInNewTab = (url) => {
@ -100,7 +100,7 @@ export default function NodeToolbarComponent({
const updateNodeInternals = useUpdateNodeInternals();
const setLastCopiedSelection = useFlowStore(
(state) => state.setLastCopiedSelection
(state) => state.setLastCopiedSelection,
);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
@ -153,7 +153,7 @@ export default function NodeToolbarComponent({
nodes,
edges,
setNodes,
setEdges
setEdges,
);
break;
case "override":
@ -177,7 +177,7 @@ export default function NodeToolbarComponent({
y: 10,
paneX: nodes.find((node) => node.id === data.id)?.position.x,
paneY: nodes.find((node) => node.id === data.id)?.position.y,
}
},
);
break;
case "update":
@ -215,13 +215,13 @@ export default function NodeToolbarComponent({
};
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 handleOnNewValue = (
newValue: string | string[] | boolean | Object[]
newValue: string | string[] | boolean | Object[],
): void => {
if (data.node!.template[name].value !== newValue) {
takeSnapshot();
@ -408,7 +408,7 @@ export default function NodeToolbarComponent({
data-testid="save-button-modal"
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",
hasCode ? " " : " rounded-l-md "
hasCode ? " " : " rounded-l-md ",
)}
onClick={(event) => {
event.preventDefault();
@ -426,7 +426,7 @@ export default function NodeToolbarComponent({
<button
data-testid="duplicate-button-modal"
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) => {
event.preventDefault();
@ -440,7 +440,7 @@ export default function NodeToolbarComponent({
<ShadTooltip content="Freeze" side="top">
<button
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) => {
event.preventDefault();
@ -461,7 +461,7 @@ export default function NodeToolbarComponent({
className={cn(
"h-4 w-4 transition-all",
// TODO UPDATE THIS COLOR TO BE A VARIABLE
frozen ? "animate-wiggle text-ice" : ""
frozen ? "animate-wiggle text-ice" : "",
)}
/>
</button>
@ -474,7 +474,7 @@ export default function NodeToolbarComponent({
<div
data-testid="more-options-modal"
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

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 (
<PageLayout

View file

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

View file

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

View file

@ -11,7 +11,7 @@ const useSaveKey = (
setErrorData,
setHasApiKey,
setValidApiKey,
setLoadingApiKey
setLoadingApiKey,
) => {
const { storeApiKey } = useContext(AuthContext);
@ -35,7 +35,7 @@ const useSaveKey = (
setHasApiKey(false);
setValidApiKey(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 LoadingComponent from "./components/loadingComponent";
import { StoreGuard } from "./components/storeGuard";
import MessagesPage from "./pages/SettingsPage/pages/messagesPage";
const AdminPage = lazy(() => import("./pages/AdminPage"));
const LoginAdminPage = lazy(() => import("./pages/AdminPage/LoginPage"));
@ -78,6 +79,7 @@ const Router = () => {
<Route path="global-variables" element={<GlobalVariablesPage />} />
<Route path="general/:scrollId?" element={<GeneralPage />} />
<Route path="shortcuts" element={<ShortcutsPage />} />
<Route path="messages" element={<MessagesPage />} />
</Route>
<Route
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;
}
.ag-paging-page-size {
display: none;
}
.react-flow__pane {
cursor: default;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -24,7 +24,7 @@ test("chat_io_teste", async ({ page }) => {
const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/ChatTest.json",
"utf-8"
"utf-8",
);
await page.getByTestId("blank-flow").click();
@ -47,7 +47,7 @@ test("chat_io_teste", async ({ page }) => {
"drop",
{
dataTransfer,
}
},
);
await page.getByLabel("fit view").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")
.nth(1)
.fill(
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!"
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!",
);
await page.getByTestId("icon-LucideSend").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
.getByText(
"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.
const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/collection.json",
"utf-8"
"utf-8",
);
// Create the DataTransfer and File
@ -47,7 +47,7 @@ test.describe("drag and drop test", () => {
"drop",
{
dataTransfer,
}
},
);
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();
expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked()
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked()
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showendpoint_url"]').click();
expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked()
await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showendpoint_url"]').click();
expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked()
await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showregion_name"]').click();
expect(
await page.locator('//*[@id="showregion_name"]').isChecked()
await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showregion_name"]').click();
expect(
await page.locator('//*[@id="showregion_name"]').isChecked()
await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeTruthy();
// showmodel_id
@ -113,7 +113,7 @@ test("dropDownComponent", async ({ page }) => {
// showmodel_id
await page.locator('//*[@id="showmodel_id"]').click();
expect(
await page.locator('//*[@id="showmodel_id"]').isChecked()
await page.locator('//*[@id="showmodel_id"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showcache"]').click();
@ -124,32 +124,32 @@ test("dropDownComponent", async ({ page }) => {
await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked()
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showcredentials_profile_name"]').click();
expect(
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked()
await page.locator('//*[@id="showcredentials_profile_name"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showendpoint_url"]').click();
expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked()
await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showendpoint_url"]').click();
expect(
await page.locator('//*[@id="showendpoint_url"]').isChecked()
await page.locator('//*[@id="showendpoint_url"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showregion_name"]').click();
expect(
await page.locator('//*[@id="showregion_name"]').isChecked()
await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showregion_name"]').click();
expect(
await page.locator('//*[@id="showregion_name"]').isChecked()
await page.locator('//*[@id="showregion_name"]').isChecked(),
).toBeTruthy();
// showmodel_id
@ -159,7 +159,7 @@ test("dropDownComponent", async ({ page }) => {
// showmodel_id
await page.locator('//*[@id="showmodel_id"]').click();
expect(
await page.locator('//*[@id="showmodel_id"]').isChecked()
await page.locator('//*[@id="showmodel_id"]').isChecked(),
).toBeTruthy();
await page.getByTestId("dropdown-edit-model_id").click();

View file

@ -40,7 +40,7 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page
.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()
.then(async () => {
@ -60,17 +60,17 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page
.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()
.then(async () => {
await expect(
page.getByTestId("tooltip-Model Specs").first()
page.getByTestId("tooltip-Model Specs").first(),
).toBeVisible();
await page.waitForTimeout(2000);
await expect(
page.getByTestId("tooltip-Model Specs").first()
page.getByTestId("tooltip-Model Specs").first(),
).toBeVisible();
await page.getByTestId("icon-Search").click();
@ -81,12 +81,12 @@ test("LLMChain - Tooltip", async ({ page }) => {
await page
.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()
.then(async () => {
await expect(
page.getByTestId("empty-tooltip-filter").first()
page.getByTestId("empty-tooltip-filter").first(),
).toBeVisible();
});
});
@ -113,7 +113,7 @@ test("LLMChain - Filter", async ({ page }) => {
await page.waitForTimeout(1000);
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();
@ -136,7 +136,7 @@ test("LLMChain - Filter", async ({ page }) => {
await page
.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();
@ -149,14 +149,14 @@ test("LLMChain - Filter", async ({ page }) => {
await expect(page.getByTestId("model_specsChatOpenAI")).toBeVisible();
await expect(page.getByTestId("model_specsChatVertexAI")).toBeVisible();
await expect(
page.getByTestId("model_specsGoogle Generative AI")
page.getByTestId("model_specsGoogle Generative AI"),
).toBeVisible();
await expect(
page.getByTestId("model_specsHugging Face Inference API")
page.getByTestId("model_specsHugging Face Inference API"),
).toBeVisible();
await expect(page.getByTestId("model_specsOllama")).toBeVisible();
await expect(
page.getByTestId("model_specsQianfanChatEndpoint")
page.getByTestId("model_specsQianfanChatEndpoint"),
).toBeVisible();
await expect(page.getByTestId("model_specsQianfanLLMEndpoint")).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("modelsAzure OpenAI")).not.toBeVisible();
await expect(
page.getByTestId("model_specsAzureChatOpenAI")
page.getByTestId("model_specsAzureChatOpenAI"),
).not.toBeVisible();
await expect(page.getByTestId("model_specsChatAnthropic")).not.toBeVisible();
await expect(page.getByTestId("model_specsChatLiteLLM")).not.toBeVisible();
@ -178,13 +178,13 @@ test("LLMChain - Filter", async ({ page }) => {
await page
.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();
await page
.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();

View file

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

View file

@ -29,7 +29,7 @@ test("flowSettings", async ({ page }) => {
await page
.getByPlaceholder("Flow name")
.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();
@ -41,7 +41,7 @@ test("flowSettings", async ({ page }) => {
await page
.getByPlaceholder("Flow description")
.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();

View file

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

View file

@ -60,69 +60,69 @@ test("InputComponent", async ({ page }) => {
expect(
await page
.locator('//*[@id="showchroma_server_cors_allow_origins"]')
.isChecked()
.isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showchroma_server_grpc_port"]').click();
expect(
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked()
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showchroma_server_host"]').click();
expect(
await page.locator('//*[@id="showchroma_server_host"]').isChecked()
await page.locator('//*[@id="showchroma_server_host"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showchroma_server_http_port"]').click();
expect(
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked()
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click();
expect(
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked()
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showcollection_name"]').click();
expect(
await page.locator('//*[@id="showcollection_name"]').isChecked()
await page.locator('//*[@id="showcollection_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showindex_directory"]').click();
expect(
await page.locator('//*[@id="showindex_directory"]').isChecked()
await page.locator('//*[@id="showindex_directory"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_cors_allow_origins"]').click();
expect(
await page
.locator('//*[@id="showchroma_server_cors_allow_origins"]')
.isChecked()
.isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_grpc_port"]').click();
expect(
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked()
await page.locator('//*[@id="showchroma_server_grpc_port"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_host"]').click();
expect(
await page.locator('//*[@id="showchroma_server_host"]').isChecked()
await page.locator('//*[@id="showchroma_server_host"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_http_port"]').click();
expect(
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked()
await page.locator('//*[@id="showchroma_server_http_port"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').click();
expect(
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked()
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showindex_directory"]').click();
expect(
await page.locator('//*[@id="showindex_directory"]').isChecked()
await page.locator('//*[@id="showindex_directory"]').isChecked(),
).toBeTruthy();
let valueEditNode = await page
@ -152,7 +152,7 @@ test("InputComponent", async ({ page }) => {
await page.locator('//*[@id="showcollection_name"]').click();
expect(
await page.locator('//*[@id="showcollection_name"]').isChecked()
await page.locator('//*[@id="showcollection_name"]').isChecked(),
).toBeTruthy();
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();
expect(
await page.getByTestId("showmetadata_indexing_exclude").isChecked()
await page.getByTestId("showmetadata_indexing_exclude").isChecked(),
).toBeFalsy();
await page.getByTestId("showmetadata_indexing_exclude").click();
expect(
await page.getByTestId("showmetadata_indexing_exclude").isChecked()
await page.getByTestId("showmetadata_indexing_exclude").isChecked(),
).toBeTruthy();
expect(
await page.getByTestId("showmetadata_indexing_include").isChecked()
await page.getByTestId("showmetadata_indexing_include").isChecked(),
).toBeFalsy();
await page.getByTestId("showmetadata_indexing_include").click();
expect(
await page.getByTestId("showmetadata_indexing_include").isChecked()
await page.getByTestId("showmetadata_indexing_include").isChecked(),
).toBeTruthy();
await page
@ -93,7 +93,7 @@ test("InputListComponent", async ({ page }) => {
.click();
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();
@ -164,12 +164,12 @@ test("InputListComponent", async ({ page }) => {
.click();
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 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();
@ -178,13 +178,13 @@ test("InputListComponent", async ({ page }) => {
}
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 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();

View file

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

View file

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

View file

@ -61,7 +61,7 @@ test("LangflowShortcuts", async ({ page }) => {
await page
.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();
await page.keyboard.press("Backspace");
@ -84,7 +84,7 @@ test("LangflowShortcuts", async ({ page }) => {
await page
.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();
await page.keyboard.press("Backspace");

View file

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

View file

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

View file

@ -27,7 +27,7 @@ test.describe("save component tests", () => {
// Read your file into a buffer.
const jsonContent = readFileSync(
"src/frontend/tests/end-to-end/assets/flow_group_test.json",
"utf-8"
"utf-8",
);
// Create the DataTransfer and File
@ -49,7 +49,7 @@ test.describe("save component tests", () => {
"drop",
{
dataTransfer,
}
},
);
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(
"Attention: API keys in specified fields are automatically removed upon sharing."
"Attention: API keys in specified fields are automatically removed upon sharing.",
)
.isVisible();
await page.getByText("Export").first().isVisible();

View file

@ -60,7 +60,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Click and hold on the first element
await page
.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();
await page.mouse.down();
@ -68,7 +68,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Move to the second element
await page
.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();
@ -92,7 +92,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Click and hold on the first element
await page
.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();
await page.mouse.down();
@ -100,7 +100,7 @@ test("TextInputOutputComponent", async ({ page }) => {
// Move to the second element
await page
.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();

View file

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