Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add pagination on folders #4020

Open
wants to merge 95 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
b24d1dc
⬆️ (uv.lock): Update authlib version from 1.3.2 to 1.3.1
Cristhianzl Oct 2, 2024
1ef65b4
✨ (flows.py): Add pagination support for retrieving a list of flows t…
Cristhianzl Oct 2, 2024
6aecb37
✨ (model.py): add PaginatedFlowResponse class to handle paginated flo…
Cristhianzl Oct 2, 2024
87e5233
✨ (test_database.py): add support for fetching all flows by adding "g…
Cristhianzl Oct 2, 2024
274135d
packages changes
Cristhianzl Oct 2, 2024
a436a58
packages changes
Cristhianzl Oct 2, 2024
47c3340
📝 (paginatorComponent/index.tsx): refactor PaginatorComponent to use …
Cristhianzl Oct 2, 2024
3e2b98b
🐛 (storeCardComponent): fix height of store card component to prevent…
Cristhianzl Oct 2, 2024
8f8a239
✨ (constants.ts): introduce new constants for search tabs, pagination…
Cristhianzl Oct 2, 2024
2102c39
✨ (use-post-login-user.ts): add queryClient to UseRequestProcessor to…
Cristhianzl Oct 2, 2024
c353365
✨ (use-get-basic-examples.ts): introduce a new query function to fetc…
Cristhianzl Oct 3, 2024
793c6d6
✨ (use-get-refresh-flows.ts): introduce new functionality to fetch an…
Cristhianzl Oct 3, 2024
957567d
✨ (use-get-folder.ts): Add support for pagination and filtering optio…
Cristhianzl Oct 3, 2024
9df2a2e
🔧 (use-get-folders.ts): Remove unused code related to refreshFlows an…
Cristhianzl Oct 3, 2024
e1eb04d
✨ (use-upload-flow.ts): update refreshFlows function call to include …
Cristhianzl Oct 3, 2024
78a8620
🔧 (codeAreaModal/index.tsx): remove unused import postCustomComponent…
Cristhianzl Oct 3, 2024
6f3ad78
📝 (AdminPage/index.tsx): Update initial page size and index values to…
Cristhianzl Oct 3, 2024
d9cb2fd
✨ (AppInitPage/index.tsx): introduce new queries to fetch basic examp…
Cristhianzl Oct 3, 2024
7e0d1b8
✨ (FlowPage/index.tsx): update refreshFlows function call to include …
Cristhianzl Oct 3, 2024
2beacc3
✨ (frontend): introduce flowsPagination and setFlowsPagination functi…
Cristhianzl Oct 3, 2024
f9a0f75
✨ (frontend): introduce new 'folders' and 'setFolders' properties to …
Cristhianzl Oct 3, 2024
65ccfa7
✨ (types.ts): introduce Pagination type to define structure for pagin…
Cristhianzl Oct 3, 2024
07cdd59
✨ (frontend): introduce PaginatedFlowsType to represent paginated flo…
Cristhianzl Oct 3, 2024
b501f2c
✨ (frontend): add optional 'pages' property to PaginatorComponentType…
Cristhianzl Oct 3, 2024
2c78060
✨ (utilityStore.ts): introduce flowsPagination object with default va…
Cristhianzl Oct 3, 2024
598f2c2
✨ (foldersStore.tsx): introduce new state 'folders' and setter functi…
Cristhianzl Oct 3, 2024
33d43b8
✨ (ViewPage/index.tsx): update refreshFlows function call to include …
Cristhianzl Oct 3, 2024
28972df
📝 (StorePage/index.tsx): update constants import to include new pagin…
Cristhianzl Oct 3, 2024
a78520c
✨ (componentsComponent/index.tsx): Add support for pagination feature…
Cristhianzl Oct 3, 2024
c75aa02
✨ (myCollectionComponent/index.tsx): introduce pagination and search …
Cristhianzl Oct 3, 2024
3e8c8f9
✨ (Playground/index.tsx): Update refreshFlows function call to includ…
Cristhianzl Oct 3, 2024
a6a170e
✨ (entities/index.tsx): introduce PaginatedFolderType to represent a …
Cristhianzl Oct 3, 2024
53a9a9e
✨ (headerTabsSearchComponent/index.tsx): add support for changing tab…
Cristhianzl Oct 3, 2024
834722b
📝 (folders.py): Remove redundant import and unused code related to Fo…
Cristhianzl Oct 3, 2024
e9d4d16
📝 (folders.py): reorganize imports to improve readability and maintai…
Cristhianzl Oct 3, 2024
588d9f1
📝 (flows.py): import FlowSummary model to support new functionality i…
Cristhianzl Oct 3, 2024
148f5ea
📝 (folders.py): remove unnecessary empty line to improve code readabi…
Cristhianzl Oct 3, 2024
62d63cb
✨ (model.py): introduce new FlowSummary class to represent a summary …
Cristhianzl Oct 3, 2024
f664b46
✨ (pagination_model.py): introduce a new model 'FolderWithPaginatedFl…
Cristhianzl Oct 3, 2024
6c8aa32
📝 (cardComponent/index.tsx): add missing semicolon to improve code co…
Cristhianzl Oct 3, 2024
2f5ddb1
✨ (use-get-refresh-flows.ts): introduce new query parameter 'header_f…
Cristhianzl Oct 3, 2024
1783794
✨ (use-get-folders.ts): add functionality to refresh flows when fetch…
Cristhianzl Oct 3, 2024
158cacb
✨ (use-upload-flow.ts): add support for fetching header flows along w…
Cristhianzl Oct 3, 2024
f1a5f8a
✨ (use-redirect-flow-card-click.tsx): introduce a new custom hook 'us…
Cristhianzl Oct 3, 2024
9434f47
✨ (NewFlowCardComponent/index.tsx): refactor onClick event handler in…
Cristhianzl Oct 3, 2024
e82340e
📝 (undrawCards/index.tsx): Remove unused imports and variables to cle…
Cristhianzl Oct 3, 2024
c4f2c49
✨ (flowsManager/index.ts): introduce new state and setter for flowToC…
Cristhianzl Oct 3, 2024
59537c1
✨ (flowsManagerStore.ts): introduce new feature to set and update the…
Cristhianzl Oct 3, 2024
20fd5da
✨ (ViewPage/index.tsx): add support for fetching header flows along w…
Cristhianzl Oct 3, 2024
eb325d8
✨ (collectionCard/index.tsx): introduce useFlowsManagerStore to manag…
Cristhianzl Oct 3, 2024
4c01f13
✨ (Playground/index.tsx): add support for fetching header flows along…
Cristhianzl Oct 3, 2024
8a184ef
🐛 (FlowPage/index.tsx): Fix setCurrentFlow logic to correctly set the…
Cristhianzl Oct 3, 2024
2ca037e
merge main
Cristhianzl Oct 3, 2024
3ef1ab9
✨ (use-get-flow.ts): introduce a new file to handle API queries for f…
Cristhianzl Oct 3, 2024
9b8ef59
📝 (flows.py): update import statement to use FlowHeader instead of Fl…
Cristhianzl Oct 3, 2024
b0c4d2b
✨ (model.py): rename FlowSummary class to FlowHeader for better clari…
Cristhianzl Oct 3, 2024
6ee2b00
✨ (use-get-folder.ts): introduce processFlows function to process flo…
Cristhianzl Oct 3, 2024
62670b9
🔧 (use-get-refresh-flows.ts): refactor useGetRefreshFlows function to…
Cristhianzl Oct 3, 2024
67b0c5c
✨ (FlowPage/index.tsx): Add useGetFlow hook to fetch flow data and up…
Cristhianzl Oct 3, 2024
be7d7a8
✨ (nodeToolbarComponent/index.tsx): improve user experience by automa…
Cristhianzl Oct 3, 2024
672e130
✨ (use-post-login-user.ts): add queryClient.refetchQueries for "useGe…
Cristhianzl Oct 3, 2024
2595325
✨ (use-get-flow.ts): add processFlows function to process flow data b…
Cristhianzl Oct 3, 2024
bd796a3
🐛 (use-get-refresh-flows.ts): fix asynchronous flow to correctly hand…
Cristhianzl Oct 3, 2024
8e16e3d
✨ (use-get-tags.ts): add functionality to set tags in utility store a…
Cristhianzl Oct 3, 2024
fc212e6
📝 (shareModal/index.tsx): Update import statement for useUtilityStore…
Cristhianzl Oct 3, 2024
c8d3fee
✨ (AppInitPage/index.tsx): introduce useGetTagsQuery to fetch tags da…
Cristhianzl Oct 3, 2024
816b32b
✨ (StorePage/index.tsx): refactor to use useUtilityStore for tags sta…
Cristhianzl Oct 3, 2024
27f82b6
✨ (frontend): introduce Tag type to UtilityStoreType and add tags and…
Cristhianzl Oct 3, 2024
a0f3631
✨ (types.ts): introduce new Tag type to represent a tag with id and n…
Cristhianzl Oct 3, 2024
a652ece
✨ (utilityStore.ts): introduce new 'tags' array and 'setTags' functio…
Cristhianzl Oct 3, 2024
3480b7d
📝 (App.css): add a blank line for better readability and consistency …
Cristhianzl Oct 3, 2024
7d4f19e
✨ (test_database.py): add pagination support for reading flows and fo…
Cristhianzl Oct 4, 2024
b3351f4
✨ (tabsComponent/index.tsx): refactor changeLocation function to use …
Cristhianzl Oct 4, 2024
0861bb5
✨ (headerTabsSearchComponent/index.tsx): refactor handleChangeTab, ha…
Cristhianzl Oct 4, 2024
cf1a3fa
✨ (myCollectionComponent/index.tsx): refactor filter state initializa…
Cristhianzl Oct 4, 2024
e1b4329
✨ (create-query-param-string.ts): introduce a new utility function to…
Cristhianzl Oct 4, 2024
1ae539e
✨ (use-get-folder.ts): introduce buildQueryStringUrl function to crea…
Cristhianzl Oct 4, 2024
8892bbc
✨ (use-delete-folders.ts): add functionality to update local store af…
Cristhianzl Oct 4, 2024
1a3f99c
📝 (use-post-add-flow.ts): import useFolderStore to access myCollectio…
Cristhianzl Oct 4, 2024
f14c91d
✨ (use-get-refresh-flows.ts): refactor addQueryParams function to use…
Cristhianzl Oct 4, 2024
31b9279
♻️ (flows.py): remove unnecessary commented out code and add paginati…
Cristhianzl Oct 4, 2024
82d57c9
Merge branch 'main' into cz/pagination-refactor
Cristhianzl Oct 4, 2024
0f8a4e9
🔧 (NodeDescription/index.tsx): remove console.log statement for bette…
Cristhianzl Oct 4, 2024
e7e3b2f
✨ (index.tsx): Add DialogClose component from @radix-ui/react-dialog …
Cristhianzl Oct 4, 2024
76c5359
♻️ (use-redirect-flow-card-click.tsx): remove unused setFlowToCanvas …
Cristhianzl Oct 4, 2024
d0f99ed
Merge branch 'cz/pagination-refactor' of https://github.com/langflow-…
Cristhianzl Oct 4, 2024
c85a667
📝 (use-patch-update-flow.ts): update onSettled callback to refetch us…
Cristhianzl Oct 4, 2024
c206926
🔧 (use-delete-folders.ts): update onSettled function to correctly ref…
Cristhianzl Oct 4, 2024
946e7fa
✨ (use-get-folder.ts): update useGetFolderQuery to include additional…
Cristhianzl Oct 4, 2024
ac8b3b2
🔧 (use-post-upload-to-folder.ts): update onSettled callback to refetc…
Cristhianzl Oct 4, 2024
92e9361
✨ (use-add-flow.ts): add functionality to refresh flows after adding …
Cristhianzl Oct 4, 2024
4603bd5
✨ (AppInitPage/index.tsx): enable fetching basic examples and tags on…
Cristhianzl Oct 4, 2024
92ad079
✨ (myCollectionComponent/index.tsx): refactor onPaginate function to …
Cristhianzl Oct 4, 2024
92d9fb1
✨ (use-get-folder.ts): add placeholderData option to useGetFolderQuer…
Cristhianzl Oct 4, 2024
fc58c6f
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 4, 2024
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
105 changes: 78 additions & 27 deletions src/backend/base/langflow/api/v1/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse
from fastapi_pagination import Page, Params, add_pagination
from fastapi_pagination.ext.sqlalchemy import paginate
from loguru import logger
from sqlmodel import Session, and_, col, select

Expand All @@ -19,6 +21,7 @@
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate
from langflow.services.database.models.flow.model import FlowHeader
from langflow.services.database.models.flow.utils import get_webhook_component_in_flow
from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME
from langflow.services.database.models.folder.model import Folder
Expand Down Expand Up @@ -120,64 +123,80 @@ def create_flow(
raise HTTPException(status_code=500, detail=str(e)) from e


@router.get("/", response_model=list[FlowRead], status_code=200)
@router.get("/", response_model=list[FlowRead] | Page[FlowRead] | list[FlowHeader], status_code=200)
def read_flows(
*,
current_user: User = Depends(get_current_active_user),
session: Session = Depends(get_session),
settings_service: SettingsService = Depends(get_settings_service),
remove_example_flows: bool = False,
components_only: bool = False,
get_all: bool = False,
folder_id: UUID | None = None,
params: Params = Depends(),
header_flows: bool = False,
):
"""
Retrieve a list of flows.
Retrieve a list of flows with pagination support.

Args:
current_user (User): The current authenticated user.
session (Session): The database session.
settings_service (SettingsService): The settings service.
remove_example_flows (bool, optional): Whether to remove example flows. Defaults to False.
components_only (bool, optional): Whether to return only components. Defaults to False.

get_all (bool, optional): Whether to return all flows without pagination. Defaults to False.
folder_id (UUID, optional): The folder ID. Defaults to None.
params (Params): Pagination parameters.
remove_example_flows (bool, optional): Whether to remove example flows. Defaults to False.
Returns:
List[Dict]: A list of flows in JSON format.
Union[list[FlowRead], Page[FlowRead]]: A list of flows or a paginated response containing the list of flows.
"""

try:
auth_settings = settings_service.auth_settings

default_folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME)).first()
default_folder_id = default_folder.id if default_folder else None

starter_folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
starter_folder_id = starter_folder.id if starter_folder else None

if not folder_id:
folder_id = default_folder_id

if auth_settings.AUTO_LOGIN:
stmt = select(Flow).where(
(Flow.user_id == None) | (Flow.user_id == current_user.id) # noqa
)
if components_only:
stmt = stmt.where(Flow.is_component == True) # noqa
flows = session.exec(stmt).all()

else:
flows = current_user.flows
stmt = select(Flow).where(Flow.user_id == current_user.id)

if remove_example_flows:
stmt = stmt.where(Flow.folder_id != starter_folder_id)

flows = validate_is_component(flows) # type: ignore
if components_only:
flows = [flow for flow in flows if flow.is_component]
flow_ids = [flow.id for flow in flows]
# with the session get the flows that DO NOT have a user_id
folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()

if not remove_example_flows and not components_only:
try:
example_flows = folder.flows if folder else []
for example_flow in example_flows:
if example_flow.id not in flow_ids:
flows.append(example_flow) # type: ignore
except Exception as e:
logger.error(e)
stmt = stmt.where(Flow.is_component == True) # noqa

if remove_example_flows:
flows = [flow for flow in flows if flow.folder_id != folder.id]
if not get_all:
stmt = stmt.where(Flow.folder_id == folder_id)

if get_all:
flows = session.exec(stmt).all()
flows = validate_is_component(flows) # type: ignore
if components_only:
flows = [flow for flow in flows if flow.is_component]
if remove_example_flows and starter_folder_id:
flows = [flow for flow in flows if flow.folder_id != starter_folder_id]
if header_flows:
return [
{"id": flow.id, "name": flow.name, "folder_id": flow.folder_id, "is_component": flow.is_component}
for flow in flows
] # type: ignore
return flows
return paginate(session, stmt, params=params)

except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return [jsonable_encoder(flow) for flow in flows]


@router.get("/{flow_id}", response_model=FlowRead, status_code=200)
Expand Down Expand Up @@ -399,3 +418,35 @@ async def download_multiple_file(
headers={"Content-Disposition": f"attachment; filename={filename}"},
)
return flows_without_api_keys[0]


@router.get("/basic_examples/", response_model=list[FlowRead], status_code=200)
def read_basic_examples(
*,
session: Session = Depends(get_session),
):
"""
Retrieve a list of basic example flows.

Args:
session (Session): The database session.

Returns:
list[FlowRead]: A list of basic example flows.
"""

try:
# Get the starter folder
starter_folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()

if not starter_folder:
return []

# Get all flows in the starter folder
return session.exec(select(Flow).where(Flow.folder_id == starter_folder.id)).all()

except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e


add_pagination(router)
30 changes: 25 additions & 5 deletions src/backend/base/langflow/api/v1/folders.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import orjson
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
from fastapi_pagination import Params
from fastapi_pagination.ext.sqlmodel import paginate
from sqlalchemy import or_, update
from sqlmodel import Session, select

Expand All @@ -8,16 +10,17 @@
from langflow.api.v1.schemas import FlowListCreate, FlowListReadWithFolderName
from langflow.helpers.flow import generate_unique_flow_name
from langflow.helpers.folders import generate_unique_folder_name
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models.flow.model import Flow, FlowCreate, FlowRead
from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME
from langflow.services.database.models.folder.model import (
Folder,
FolderCreate,
FolderRead,
FolderReadWithFlows,
FolderUpdate,
)
from langflow.services.database.models.folder.pagination_model import FolderWithPaginatedFlows
from langflow.services.database.models.user.model import User
from langflow.services.deps import get_session

Expand Down Expand Up @@ -89,25 +92,42 @@ def read_folders(
or_(Folder.user_id == current_user.id, Folder.user_id == None) # type: ignore # noqa: E711
)
).all()
folders = [folder for folder in folders if folder.name != STARTER_FOLDER_NAME]
return sorted(folders, key=lambda x: x.name != DEFAULT_FOLDER_NAME)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e


@router.get("/{folder_id}", response_model=FolderReadWithFlows, status_code=200)
@router.get("/{folder_id}", response_model=FolderWithPaginatedFlows, status_code=200)
def read_folder(
*,
session: Session = Depends(get_session),
folder_id: str,
current_user: User = Depends(get_current_active_user),
params: Params = Depends(),
is_component: bool = False,
is_flow: bool = False,
search: str = "",
):
try:
folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
flows_from_current_user_in_folder = [flow for flow in folder.flows if flow.user_id == current_user.id]
folder.flows = flows_from_current_user_in_folder
return folder

stmt = (
select(Flow)
.where(Flow.folder_id == folder_id, Flow.user_id == current_user.id)
.order_by(Flow.updated_at.desc()) # type: ignore
)
if is_component:
stmt = stmt.where(Flow.is_component == True) # type: ignore # noqa: E712
if is_flow:
stmt = stmt.where(Flow.is_component == False) # type: ignore # noqa: E712
if search:
stmt = stmt.where(Flow.name.like(f"%{search}%")) # type: ignore
paginated_flows = paginate(session, stmt, params=params)

return FolderWithPaginatedFlows(folder=FolderRead.model_validate(folder), flows=paginated_flows)
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found") from e
Expand Down
16 changes: 15 additions & 1 deletion src/backend/base/langflow/services/database/models/flow/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from emoji import purely_emoji # type: ignore
from fastapi import HTTPException, status
from loguru import logger
from pydantic import field_serializer, field_validator
from pydantic import BaseModel, field_serializer, field_validator
from sqlalchemy import Text, UniqueConstraint
from sqlmodel import JSON, Column, Field, Relationship, SQLModel

Expand Down Expand Up @@ -188,6 +188,20 @@ class FlowRead(FlowBase):
folder_id: UUID | None = Field()


class FlowHeader(BaseModel):
id: UUID
name: str
folder_id: UUID | None = Field()
is_component: bool | None = Field()


class PaginatedFlowResponse(BaseModel):
flows: list[FlowRead]
total: int
page_size: int
page_index: int


class FlowUpdate(SQLModel):
name: str | None = None
description: str | None = None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from fastapi_pagination import Page

from langflow.helpers.base_model import BaseModel
from langflow.services.database.models.flow.model import Flow
from langflow.services.database.models.folder.model import FolderRead


class FolderWithPaginatedFlows(BaseModel):
folder: FolderRead
flows: Page[Flow]
3 changes: 2 additions & 1 deletion src/backend/base/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ dependencies = [
"spider-client>=0.0.27",
"diskcache>=5.6.3",
"clickhouse-connect==0.7.19",
"assemblyai>=0.33.0"
"assemblyai>=0.33.0",
"fastapi-pagination>=0.12.29",
]

# Optional dependencies for uv
Expand Down
72 changes: 70 additions & 2 deletions src/backend/tests/unit/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,30 @@ async def test_read_flows(client: TestClient, json_flow: str, active_user, logge
assert len(response.json()) > 0


async def test_read_flows_pagination(client: TestClient, json_flow: str, active_user, logged_in_headers):
response = await client.get("api/v1/flows/", headers=logged_in_headers)
assert response.status_code == 200
assert response.json()["page"] == 1
assert response.json()["size"] == 50
assert response.json()["pages"] == 0
assert response.json()["total"] == 0
assert len(response.json()["items"]) == 0


async def test_read_flows_pagination_with_params(client: TestClient, json_flow: str, active_user, logged_in_headers):
response = await client.get("api/v1/flows/", headers=logged_in_headers, params={"page": 3, "size": 10})
assert response.status_code == 200
assert response.json()["page"] == 3
assert response.json()["size"] == 10
assert response.json()["pages"] == 0
assert response.json()["total"] == 0
assert len(response.json()["items"]) == 0


async def test_read_flows_components_only(client: TestClient, flow_component: dict, logged_in_headers):
response = await client.get("api/v1/flows/", headers=logged_in_headers, params={"components_only": True})
response = await client.get(
"api/v1/flows/", headers=logged_in_headers, params={"components_only": True, "get_all": True}
)
assert response.status_code == 200
names = [flow["name"] for flow in response.json()]
assert any("Chat Input Component" in name for name in names)
Expand Down Expand Up @@ -267,6 +289,52 @@ async def test_delete_folder_with_flows_with_transaction_and_build(
assert response.json() == {"vertex_builds": {}}


async def test_get_flows_from_folder_pagination(client: TestClient, logged_in_headers):
# Create a new folder
folder_name = f"Test Folder {uuid4()}"
folder = FolderCreate(name=folder_name, description="Test folder description", components_list=[], flows_list=[])

response = await client.post("api/v1/folders/", json=folder.model_dump(), headers=logged_in_headers)
assert response.status_code == 201, f"Expected status code 201, but got {response.status_code}"

created_folder = response.json()
folder_id = created_folder["id"]

response = await client.get(f"api/v1/folders/{folder_id}", headers=logged_in_headers)
assert response.status_code == 200
assert response.json()["folder"]["name"] == folder_name
assert response.json()["folder"]["description"] == "Test folder description"
assert response.json()["flows"]["page"] == 1
assert response.json()["flows"]["size"] == 50
assert response.json()["flows"]["pages"] == 0
assert response.json()["flows"]["total"] == 0
assert len(response.json()["flows"]["items"]) == 0


async def test_get_flows_from_folder_pagination_with_params(client: TestClient, logged_in_headers):
# Create a new folder
folder_name = f"Test Folder {uuid4()}"
folder = FolderCreate(name=folder_name, description="Test folder description", components_list=[], flows_list=[])

response = await client.post("api/v1/folders/", json=folder.model_dump(), headers=logged_in_headers)
assert response.status_code == 201, f"Expected status code 201, but got {response.status_code}"

created_folder = response.json()
folder_id = created_folder["id"]

response = await client.get(
f"api/v1/folders/{folder_id}", headers=logged_in_headers, params={"page": 3, "size": 10}
)
assert response.status_code == 200
assert response.json()["folder"]["name"] == folder_name
assert response.json()["folder"]["description"] == "Test folder description"
assert response.json()["flows"]["page"] == 3
assert response.json()["flows"]["size"] == 10
assert response.json()["flows"]["pages"] == 0
assert response.json()["flows"]["total"] == 0
assert len(response.json()["flows"]["items"]) == 0


async def test_create_flows(client: TestClient, session: Session, json_flow: str, logged_in_headers):
flow = orjson.loads(json_flow)
data = flow["data"]
Expand Down Expand Up @@ -412,7 +480,7 @@ async def test_delete_nonexistent_flow(client: TestClient, active_user, logged_i


async def test_read_only_starter_projects(client: TestClient, active_user, logged_in_headers):
response = await client.get("api/v1/flows/", headers=logged_in_headers)
response = await client.get("api/v1/flows/basic_examples/", headers=logged_in_headers)
starter_projects = load_starter_projects()
assert response.status_code == 200
assert len(response.json()) == len(starter_projects)
Expand Down
1 change: 0 additions & 1 deletion src/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ body {
width: 100%;
height: 100%;
}

.react-flow__resize-control.handle {
width: 0.75rem !important;
height: 0.75rem !important;
Expand Down
Loading
Loading