fix: set folder id on flows imported on startup (#4018)

* set folder id on flows imported on startup
---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Jordan Frazier 2024-10-04 10:19:08 -07:00 • committed by GitHub
commit 7fe478e4b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 41 additions and 2 deletions

View file

@ -20,7 +20,10 @@ from langflow.graph.graph.base import Graph
from langflow.services.auth.utils import create_super_user from langflow.services.auth.utils import create_super_user
from langflow.services.database.models.flow.model import Flow, FlowCreate from langflow.services.database.models.flow.model import Flow, FlowCreate
from langflow.services.database.models.folder.model import Folder, FolderCreate from langflow.services.database.models.folder.model import Folder, FolderCreate
from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist from langflow.services.database.models.folder.utils import (
create_default_folder_if_it_doesnt_exist,
get_default_folder_id,
)
from langflow.services.database.models.user.crud import get_user_by_username from langflow.services.database.models.user.crud import get_user_by_username
from langflow.services.deps import get_settings_service, get_storage_service, get_variable_service, session_scope from langflow.services.deps import get_settings_service, get_storage_service, get_variable_service, session_scope
from langflow.template.field.prompt import DEFAULT_PROMPT_INTUT_TYPES from langflow.template.field.prompt import DEFAULT_PROMPT_INTUT_TYPES
@ -497,6 +500,12 @@ def _is_valid_uuid(val):
def load_flows_from_directory(): def load_flows_from_directory():
"""
On langflow startup, this loads all flows from the directory specified in the settings.
All flows are uploaded into the default folder for the superuser.
Note that this feature currently only works if AUTO_LOGIN is enabled in the settings.
"""
settings_service = get_settings_service() settings_service = get_settings_service()
flows_path = settings_service.settings.load_flows_path flows_path = settings_service.settings.load_flows_path
if not flows_path: if not flows_path:
@ -522,6 +531,7 @@ def load_flows_from_directory():
existing = find_existing_flow(session, flow_id, flow_endpoint_name) existing = find_existing_flow(session, flow_id, flow_endpoint_name)
if existing: if existing:
logger.debug(f"Found existing flow: {existing.name}")
logger.info(f"Updating existing flow: {flow_id} with endpoint name {flow_endpoint_name}") logger.info(f"Updating existing flow: {flow_id} with endpoint name {flow_endpoint_name}")
for key, value in flow.items(): for key, value in flow.items():
if hasattr(existing, key): if hasattr(existing, key):
@ -529,10 +539,23 @@ def load_flows_from_directory():
setattr(existing, key, value) setattr(existing, key, value)
existing.updated_at = datetime.now(tz=timezone.utc).astimezone() existing.updated_at = datetime.now(tz=timezone.utc).astimezone()
existing.user_id = user_id existing.user_id = user_id
# Generally, folder_id should not be None, but we must check this due to the previous
# behavior where flows could be added and folder_id was None, orphaning
# them within Langflow.
if existing.folder_id is None:
folder_id = get_default_folder_id(session, user_id)
existing.folder_id = folder_id
session.add(existing) session.add(existing)
else: else:
logger.info(f"Creating new flow: {flow_id} with endpoint name {flow_endpoint_name}") logger.info(f"Creating new flow: {flow_id} with endpoint name {flow_endpoint_name}")
# Current behavior loads all new flows into default folder
folder_id = get_default_folder_id(session, user_id)
flow["user_id"] = user_id flow["user_id"] = user_id
flow["folder_id"] = folder_id
flow = Flow.model_validate(flow, from_attributes=True) flow = Flow.model_validate(flow, from_attributes=True)
flow.updated_at = datetime.now(tz=timezone.utc).astimezone() flow.updated_at = datetime.now(tz=timezone.utc).astimezone()
session.add(flow) session.add(flow)
@ -540,11 +563,14 @@ def load_flows_from_directory():
def find_existing_flow(session, flow_id, flow_endpoint_name): def find_existing_flow(session, flow_id, flow_endpoint_name):
if flow_endpoint_name: if flow_endpoint_name:
logger.debug(f"flow_endpoint_name: {flow_endpoint_name}")
stmt = select(Flow).where(Flow.endpoint_name == flow_endpoint_name) stmt = select(Flow).where(Flow.endpoint_name == flow_endpoint_name)
if existing := session.exec(stmt).first(): if existing := session.exec(stmt).first():
logger.debug(f"Found existing flow by endpoint name: {existing.name}")
return existing return existing
stmt = select(Flow).where(Flow.id == flow_id) stmt = select(Flow).where(Flow.id == flow_id)
if existing := session.exec(stmt).first(): if existing := session.exec(stmt).first():
logger.debug(f"Found existing flow by id: {flow_id}")
return existing return existing
return None return None

View file

@ -11,7 +11,11 @@ from .model import Folder
def create_default_folder_if_it_doesnt_exist(session: Session, user_id: UUID): def create_default_folder_if_it_doesnt_exist(session: Session, user_id: UUID):
folder = session.exec(select(Folder).where(Folder.user_id == user_id)).first() folder = session.exec(select(Folder).where(Folder.user_id == user_id)).first()
if not folder: if not folder:
folder = Folder(name=DEFAULT_FOLDER_NAME, user_id=user_id, description=DEFAULT_FOLDER_DESCRIPTION) folder = Folder(
name=DEFAULT_FOLDER_NAME,
user_id=user_id,
description=DEFAULT_FOLDER_DESCRIPTION,
)
session.add(folder) session.add(folder)
session.commit() session.commit()
session.refresh(folder) session.refresh(folder)
@ -27,3 +31,10 @@ def create_default_folder_if_it_doesnt_exist(session: Session, user_id: UUID):
) )
session.commit() session.commit()
return folder return folder
def get_default_folder_id(session: Session, user_id: UUID):
folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME, Folder.user_id == user_id)).first()
if not folder:
folder = create_default_folder_if_it_doesnt_exist(session, user_id)
return folder.id

View file

@ -423,11 +423,13 @@ async def test_load_flows(client: TestClient, load_flows_dir):
response = await client.get("api/v1/flows/c54f9130-f2fa-4a3e-b22a-3856d946351b") response = await client.get("api/v1/flows/c54f9130-f2fa-4a3e-b22a-3856d946351b")
assert response.status_code == 200 assert response.status_code == 200
assert response.json()["name"] == "BasicExample" assert response.json()["name"] == "BasicExample"
assert response.json()["folder_id"] is not None
# re-run to ensure updates work well # re-run to ensure updates work well
load_flows_from_directory() load_flows_from_directory()
response = await client.get("api/v1/flows/c54f9130-f2fa-4a3e-b22a-3856d946351b") response = await client.get("api/v1/flows/c54f9130-f2fa-4a3e-b22a-3856d946351b")
assert response.status_code == 200 assert response.status_code == 200
assert response.json()["name"] == "BasicExample" assert response.json()["name"] == "BasicExample"
assert response.json()["folder_id"] is not None
def test_sqlite_pragmas(): def test_sqlite_pragmas():