Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 20 additions & 12 deletions backend/apps/group_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ async def get_groups_endpoint(
Search groups for a specific tenant with pagination

Args:
request: Group search request with tenant_id, page, and page_size
request: Group search request with tenant_id, optional page, and page_size.
If page and page_size are not provided, returns all data.

Returns:
JSONResponse: Paginated list of groups for the tenant
JSONResponse: List of groups for the tenant (paginated or all)
"""
try:
# Validate tenant exists
Expand All @@ -150,18 +151,25 @@ async def get_groups_endpoint(
sort_order=request.sort_order
)

# Build response content
content = {
"message": "Groups retrieved successfully",
"data": result["groups"],
"total": result["total"]
}

# Add pagination info only if pagination was used
if request.page is not None and request.page_size is not None:
content["pagination"] = {
"page": request.page,
"page_size": request.page_size,
"total": result["total"],
"total_pages": (result["total"] + request.page_size - 1) // request.page_size
}

return JSONResponse(
status_code=HTTPStatus.OK,
content={
"message": "Groups retrieved successfully",
"data": result["groups"],
"pagination": {
"page": request.page,
"page_size": request.page_size,
"total": result["total"],
"total_pages": (result["total"] + request.page_size - 1) // request.page_size
}
}
content=content
)

except NotFoundException as exc:
Expand Down
32 changes: 20 additions & 12 deletions backend/apps/user_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,36 @@ async def get_users_endpoint(
Get users belonging to a specific tenant with pagination

Args:
request: User list request with tenant_id, page, and page_size
request: User list request with tenant_id, optional page, and page_size.
If page and page_size are not provided, returns all data.

Returns:
JSONResponse: Paginated list of users in the tenant
JSONResponse: List of users in the tenant (paginated or all)
"""
try:
# Get tenant users with pagination and sorting
result = get_users(request.tenant_id, request.page, request.page_size,
request.sort_by, request.sort_order)

# Build response content
content = {
"message": "Users retrieved successfully",
"data": result["users"],
"total": result["total"]
}

# Add pagination info only if pagination was used
if request.page is not None and request.page_size is not None:
content["pagination"] = {
"page": request.page,
"page_size": request.page_size,
"total": result["total"],
"total_pages": result.get("total_pages", (result["total"] + request.page_size - 1) // request.page_size)
}

return JSONResponse(
status_code=HTTPStatus.OK,
content={
"message": "Users retrieved successfully",
"data": result["users"],
"pagination": {
"page": request.page,
"page_size": request.page_size,
"total": result["total"],
"total_pages": result["total_pages"]
}
}
content=content
)
except Exception as exc:
logger.error(f"Unexpected error retrieving users for tenant {request.tenant_id}: {str(exc)}")
Expand Down
26 changes: 16 additions & 10 deletions backend/consts/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,21 +537,27 @@ class GroupUpdateRequest(BaseModel):
class GroupListRequest(BaseModel):
"""Request model for listing groups"""
tenant_id: str = Field(..., description="Tenant ID to filter groups")
page: int = Field(1, ge=1, description="Page number for pagination")
page_size: int = Field(
20, ge=1, le=100, description="Number of items per page")
sort_by: Optional[str] = Field("created_at", description="Field to sort by")
sort_order: Optional[str] = Field("desc", description="Sort order (asc or desc)")
page: Optional[int] = Field(
None, ge=1, description="Page number for pagination. If not provided, returns all data")
page_size: Optional[int] = Field(
None, ge=1, le=100, description="Number of items per page. If not provided, returns all data")
sort_by: Optional[str] = Field(
"created_at", description="Field to sort by")
sort_order: Optional[str] = Field(
"desc", description="Sort order (asc or desc)")


class UserListRequest(BaseModel):
"""Request model for listing users"""
tenant_id: str = Field(..., description="Tenant ID to filter users")
page: int = Field(1, ge=1, description="Page number for pagination")
page_size: int = Field(
20, ge=1, le=100, description="Number of items per page")
sort_by: Optional[str] = Field("created_at", description="Field to sort by")
sort_order: Optional[str] = Field("desc", description="Sort order (asc or desc)")
page: Optional[int] = Field(
None, ge=1, description="Page number for pagination. If not provided, returns all data")
page_size: Optional[int] = Field(
None, ge=1, le=100, description="Number of items per page. If not provided, returns all data")
sort_by: Optional[str] = Field(
"created_at", description="Field to sort by")
sort_order: Optional[str] = Field(
"desc", description="Sort order (asc or desc)")


class GroupUserRequest(BaseModel):
Expand Down
19 changes: 11 additions & 8 deletions backend/database/group_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,21 @@ def query_groups(group_id: Union[int, str, List[int]]) -> Union[Optional[Dict[st
return groups


def query_groups_by_tenant(tenant_id: str, page: int = 1, page_size: int = 20,
def query_groups_by_tenant(tenant_id: str, page: Optional[int] = 1, page_size: Optional[int] = 20,
sort_by: str = "created_at", sort_order: str = "desc") -> Dict[str, Any]:
"""
Query groups for a tenant with pagination and sorting
Args:
tenant_id (str): Tenant ID
page (int): Page number (1-based)
page_size (int): Number of items per page
page (Optional[int]): Page number (1-based). If None, returns all data
page_size (Optional[int]): Number of items per page. If None, returns all data
sort_by (str): Field to sort by
sort_order (str): Sort order (asc or desc)
Returns:
Dict[str, Any]: Dictionary containing groups list and total count
"""
offset = (page - 1) * page_size

with get_db_session() as session:
# Get total count
total = session.query(TenantGroupInfo).filter(
Expand All @@ -86,8 +84,13 @@ def query_groups_by_tenant(tenant_id: str, page: int = 1, page_size: int = 20,
else:
query = query.order_by(TenantGroupInfo.create_time.asc())

# Get paginated results
result = query.offset(offset).limit(page_size).all()
# Apply pagination only if both page and page_size are provided
if page is not None and page_size is not None:
offset = (page - 1) * page_size
result = query.offset(offset).limit(page_size).all()
else:
# Return all results when pagination is not specified
result = query.all()

return {
"groups": [as_dict(record) for record in result],
Expand Down Expand Up @@ -401,4 +404,4 @@ def check_group_name_exists(tenant_id: str, group_name: str, exclude_group_id: O
query = query.filter(TenantGroupInfo.group_id != exclude_group_id)

result = query.first()
return result is not None
return result is not None
18 changes: 11 additions & 7 deletions backend/database/user_tenant_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ def insert_user_tenant(user_id: str, tenant_id: str, user_role: str = "USER", us
session.add(user_tenant)


def get_users_by_tenant_id(tenant_id: str, page: int = 1, page_size: int = 20,
def get_users_by_tenant_id(tenant_id: str, page: Optional[int] = 1, page_size: Optional[int] = 20,
sort_by: str = "created_at", sort_order: str = "desc") -> Dict[str, Any]:
"""
Get users belonging to a specific tenant with pagination and sorting

Args:
tenant_id (str): Tenant ID
page (int): Page number (1-based)
page_size (int): Number of items per page
page (Optional[int]): Page number (1-based). If None, returns all data
page_size (Optional[int]): Number of items per page. If None, returns all data
sort_by (str): Field to sort by
sort_order (str): Sort order (asc or desc)

Expand All @@ -110,9 +110,13 @@ def get_users_by_tenant_id(tenant_id: str, page: int = 1, page_size: int = 20,
else:
query = query.order_by(UserTenant.create_time.asc())

# Get paginated results
offset = (page - 1) * page_size
results = query.offset(offset).limit(page_size).all()
# Apply pagination only if both page and page_size are provided
if page is not None and page_size is not None:
offset = (page - 1) * page_size
results = query.offset(offset).limit(page_size).all()
else:
# Return all results when pagination is not specified
results = query.all()

return {
"users": [as_dict(row) for row in results],
Expand Down Expand Up @@ -191,4 +195,4 @@ def soft_delete_users_by_tenant_id(tenant_id: str, deleted_by: str) -> bool:
})

logger.info(f"Soft deleted {result} user-tenant relationships for tenant {tenant_id}")
return result > 0
return result > 0
6 changes: 3 additions & 3 deletions backend/services/group_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ def get_group_info(group_id: Union[int, str, List[int]]) -> Union[Optional[Dict[
return result


def get_groups_by_tenant(tenant_id: str, page: int = 1, page_size: int = 20,
def get_groups_by_tenant(tenant_id: str, page: Optional[int] = 1, page_size: Optional[int] = 20,
sort_by: str = "created_at", sort_order: str = "desc") -> Dict[str, Any]:
"""
Get groups for a specific tenant with pagination and sorting.

Args:
tenant_id (str): Tenant ID
page (int): Page number (1-based)
page_size (int): Number of items per page
page (Optional[int]): Page number (1-based). If None, returns all data
page_size (Optional[int]): Number of items per page. If None, returns all data
sort_by (str): Field to sort by
sort_order (str): Sort order (asc or desc)

Expand Down
29 changes: 18 additions & 11 deletions backend/services/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
User service layer - handles user-related business logic
"""
import logging
from typing import Dict, Any, List
from typing import Dict, Any, List, Optional

from database.user_tenant_db import (
get_users_by_tenant_id, update_user_tenant_role, get_user_tenant_by_user_id,
Expand All @@ -19,15 +19,15 @@
logger = logging.getLogger(__name__)


def get_users(tenant_id: str, page: int = 1, page_size: int = 20,
def get_users(tenant_id: str, page: Optional[int] = 1, page_size: Optional[int] = 20,
sort_by: str = "created_at", sort_order: str = "desc") -> Dict[str, Any]:
"""
Get users belonging to a specific tenant with pagination and sorting

Args:
tenant_id (str): Tenant ID
page (int): Page number (1-based)
page_size (int): Number of items per page
page (Optional[int]): Page number (1-based). If None, returns all data
page_size (Optional[int]): Number of items per page. If None, returns all data
sort_by (str): Field to sort by
sort_order (str): Sort order (asc or desc)

Expand All @@ -49,13 +49,20 @@ def get_users(tenant_id: str, page: int = 1, page_size: int = 20,
}
users.append(user_info)

return {
"users": users,
"total": result["total"],
"page": page,
"page_size": page_size,
"total_pages": (result["total"] + page_size - 1) // page_size
}
# Calculate pagination info only if pagination is used
if page is not None and page_size is not None:
return {
"users": users,
"total": result["total"],
"page": page,
"page_size": page_size,
"total_pages": (result["total"] + page_size - 1) // page_size
}
else:
return {
"users": users,
"total": result["total"]
}


async def update_user(user_id: str, update_data: Dict[str, Any], updated_by: str) -> Dict[str, Any]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default function AgentGenerateDetail({
// Tenant & group data for group selection
const { data: tenantData } = useTenantList();
const tenantId = user?.tenantId ?? tenantData?.data?.[0]?.tenant_id ?? null;
const { data: groupData } = useGroupList(tenantId, 1, 100);
const { data: groupData } = useGroupList(tenantId);

// Agent list for name uniqueness validation (use local data instead of API call)
const { agents: agentList } = useAgentList(tenantId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const DocumentListContainer = forwardRef<DocumentListRef, DocumentListProps>(
const tenantId = user?.tenantId || null;

// Fetch groups for group selection
const { data: groupData } = useGroupList(tenantId, 1, 100);
const { data: groupData } = useGroupList(tenantId);
const groups = groupData?.groups || [];

// Create group name mapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function KnowledgeBaseEditModal({
const originalNameRef = useRef<string>("");

// Fetch groups for group selection
const { data: groupData } = useGroupList(tenantId, 1, 100);
const { data: groupData } = useGroupList(tenantId);
const groups = groupData?.groups || [];

// Reset form and states when knowledge base changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const KnowledgeBaseList: React.FC<KnowledgeBaseListProps> = ({
const tenantId = user?.tenantId || null;

// Fetch groups for group name mapping
const { data: groupData } = useGroupList(tenantId, 1, 100);
const { data: groupData } = useGroupList(tenantId);
const groups = groupData?.groups || [];

// Create group name mapping from group_id to group_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default function AgentList({ tenantId }: { tenantId: string | null }) {
const { agents, isLoading, refetch } = useAgentList(tenantId);

// Fetch groups for group name mapping and selection
const { data: groupData } = useGroupList(tenantId, 1, 100);
const { data: groupData } = useGroupList(tenantId);
const groups = groupData?.groups || [];

// Create group name mapping
Expand Down
Loading
Loading