Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d26448f
🐛 (flows.py): Fix issue where flow data was not being properly update…
Cristhianzl Jan 2, 2025
f187fb7
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 2, 2025
776b594
✨ (sideBarFolderButtons/index.tsx): add unique id attribute to sideba…
Cristhianzl Jan 2, 2025
fbeebe1
Merge branch 'cz/fix-move-flow-folder' of https://github.com/langflow…
Cristhianzl Jan 2, 2025
57d562b
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 2, 2025
60e1bdd
🐛 (flows.py): remove unnecessary session rollback to prevent potentia…
Cristhianzl Jan 3, 2025
f1e811e
Merge branch 'cz/fix-move-flow-folder' of https://github.com/langflow…
Cristhianzl Jan 3, 2025
5f79e98
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 6, 2025
a6ba7d0
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 7, 2025
577dded
style: adjust line breaks for readability
italojohnny Jan 7, 2025
b77af9a
style: reorder imports
italojohnny Jan 7, 2025
9f9a32d
fix: ruff error try300
italojohnny Jan 7, 2025
b0cd684
Merge branch 'main' into cz/fix-move-flow-folder
italojohnny Jan 7, 2025
554bb45
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 7, 2025
3e60ca4
fix: mypy error module has no attribute "timeout"
italojohnny Jan 7, 2025
333bd75
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 8, 2025
ad39beb
merge fix
Cristhianzl Jan 8, 2025
39d4611
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 8, 2025
ce44e06
🐛 (flows.py): remove unnecessary error handling code and improve exce…
Cristhianzl Jan 8, 2025
3da08ad
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 8, 2025
f6c6f3d
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 8, 2025
204e758
Update src/backend/base/langflow/services/database/service.py
Cristhianzl Jan 10, 2025
fe22684
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 10, 2025
2c79708
use model dump besides overwrite value
Cristhianzl Jan 13, 2025
ae8f06c
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 13, 2025
2ec87fb
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 13, 2025
fb7fdf8
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 13, 2025
4ac90e8
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 13, 2025
af7d3f4
📝 (chat.py): improve code readability by refactoring session handling…
Cristhianzl Jan 13, 2025
e2e0a96
Merge branch 'cz/fix-move-flow-folder' of https://github.com/langflow…
Cristhianzl Jan 13, 2025
40f8416
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 13, 2025
619f18d
Merge branch 'main' into cz/fix-move-flow-folder
Cristhianzl Jan 13, 2025
123f52e
refactor: remove unused session parameter from build_flow function in…
ogabrielluiz Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/backend/base/langflow/api/v1/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ async def build_flow(
start_component_id: str | None = None,
log_builds: bool | None = True,
current_user: CurrentActiveUser,
session: DbSession,
):
chat_service = get_chat_service()
telemetry_service = get_telemetry_service()
Expand All @@ -164,15 +163,20 @@ async def build_graph_and_get_order() -> tuple[list[str], list[str], Graph]:
components_count = None
try:
flow_id_str = str(flow_id)
if not data:
graph = await build_graph_from_db(flow_id=flow_id, session=session, chat_service=chat_service)
else:
async with session_scope() as new_session:
result = await new_session.exec(select(Flow.name).where(Flow.id == flow_id))
# Create a fresh session for database operations
async with session_scope() as fresh_session:
if not data:
graph = await build_graph_from_db(flow_id=flow_id, session=fresh_session, chat_service=chat_service)
else:
result = await fresh_session.exec(select(Flow.name).where(Flow.id == flow_id))
flow_name = result.first()
graph = await build_graph_from_data(
flow_id=flow_id_str, payload=data.model_dump(), user_id=str(current_user.id), flow_name=flow_name
)
graph = await build_graph_from_data(
flow_id=flow_id_str,
payload=data.model_dump(),
user_id=str(current_user.id),
flow_name=flow_name,
)

graph.validate_stream()
if stop_component_id or start_component_id:
try:
Expand Down
25 changes: 13 additions & 12 deletions src/backend/base/langflow/api/v1/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,18 +271,18 @@ async def update_flow(
user_id=current_user.id,
settings_service=settings_service,
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e

if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found")
if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found")

update_data = flow.model_dump(exclude_unset=True, exclude_none=True)

try:
flow_data = flow.model_dump(exclude_unset=True)
if settings_service.settings.remove_api_keys:
flow_data = remove_api_keys(flow_data)
for key, value in flow_data.items():
update_data = remove_api_keys(update_data)

for key, value in update_data.items():
setattr(db_flow, key, value)

webhook_component = get_webhook_component_in_flow(db_flow.data)
db_flow.webhook = webhook_component is not None
db_flow.updated_at = datetime.now(timezone.utc)
Expand All @@ -291,24 +291,25 @@ async def update_flow(
default_folder = (await session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME))).first()
if default_folder:
db_flow.folder_id = default_folder.id

session.add(db_flow)
await session.commit()
await session.refresh(db_flow)

except Exception as e:
# If it is a validation error, return the error message
if hasattr(e, "errors"):
raise HTTPException(status_code=400, detail=str(e)) from e
if "UNIQUE constraint failed" in str(e):
# Get the name of the column that failed
columns = str(e).split("UNIQUE constraint failed: ")[1].split(".")[1].split("\n")[0]
# UNIQUE constraint failed: flow.user_id, flow.name
# or UNIQUE constraint failed: flow.name
# if the column has id in it, we want the other column
column = columns.split(",")[1] if "id" in columns.split(",")[0] else columns.split(",")[0]

raise HTTPException(
status_code=400, detail=f"{column.capitalize().replace('_', ' ')} must be unique"
) from e

if hasattr(e, "status_code"):
raise HTTPException(status_code=e.status_code, detail=str(e)) from e
raise HTTPException(status_code=500, detail=str(e)) from e

return db_flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

def get_webhook_component_in_flow(flow_data: dict):
"""Get webhook component in flow data."""
for node in flow_data.get("nodes", []):
if "Webhook" in node.get("id"):
return node
if hasattr(flow_data, "nodes"):
for node in flow_data.get("nodes", []):
if "Webhook" in node.get("id"):
return node
return None


Expand Down
9 changes: 8 additions & 1 deletion src/backend/base/langflow/services/database/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,14 @@ def on_connection(self, dbapi_connection, _connection_record) -> None:
@asynccontextmanager
async def with_session(self):
async with AsyncSession(self.engine, expire_on_commit=False) as session:
yield session
try:
yield session
if session.is_active:
await session.commit()
except Exception:
logger.error("An error occurred during the session scope.")
await session.rollback()
raise

async def assign_orphaned_flows_to_superuser(self) -> None:
"""Assign orphaned flows to the default superuser when auto login is enabled."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ const SideBarFoldersButtonsComponent = ({
onDrop={(e) => onDrop(e, item.id!)}
key={item.id}
data-testid={`sidebar-nav-${item.name}`}
id={`sidebar-nav-${item.name}`}
isActive={checkPathName(item.id!)}
onClick={() => handleChangeFolder!(item.id!)}
className={cn(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { expect, test } from "@playwright/test";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";

test("user must be able to move flow from folder", async ({ page }) => {
const randomName = Math.random().toString(36).substring(2, 15);

await awaitBootstrapTest(page);

await page.getByTestId("side_nav_options_all-templates").click();
await page.getByRole("heading", { name: "Basic Prompting" }).click();

await page.waitForSelector('[data-testid="flow_name"]', {
timeout: 3000,
});

await page.getByTestId("flow_name").click();
await page.getByText("Flow Settings").first().click();
await page.getByPlaceholder("Flow name").fill(randomName);

await page.getByTestId("save-flow-settings").click();

await page.getByText("Changes saved successfully").isVisible();

await page.getByTestId("icon-ChevronLeft").click();
await page.waitForSelector('[data-testid="add-folder-button"]', {
timeout: 3000,
});

await page.getByTestId("add-folder-button").click();

//wait for the folder to be created and changed to the new folder
await page.waitForTimeout(1000);

await page.getByTestId("sidebar-nav-My Projects").click();

await page.getByText(randomName).hover();

await page
.getByTestId("list-card")
.first()
.dragTo(page.locator('//*[@id="sidebar-nav-New Folder"]'));

//wait for the drag and drop to be completed
await page.waitForTimeout(1000);

await page.getByTestId("sidebar-nav-New Folder").click();

await page.waitForSelector('[data-testid="list-card"]', {
timeout: 3000,
});

const flowNameCount = await page.getByText(randomName).count();
expect(flowNameCount).toBeGreaterThan(0);
});
Loading