@@ -8776,9 +8776,11 @@ async def admin_tool_ops_partial(
87768776@admin_router.get("/tools/ids", response_class=JSONResponse)
87778777@require_permission("tools.read", allow_admin_bypass=False)
87788778async def admin_get_all_tool_ids(
8779+ q: str = Query("", description="Search query"),
87798780 include_inactive: bool = False,
87808781 gateway_id: Optional[str] = Query(None, description="Filter by gateway ID(s), comma-separated"),
87818782 team_id: Optional[str] = Depends(_validated_team_id_param),
8783+ include_public: bool = False,
87828784 db: Session = Depends(get_db),
87838785 user=Depends(get_current_user_with_permissions),
87848786):
@@ -8788,9 +8790,11 @@ async def admin_get_all_tool_ids(
87888790 This is used by "Select All" to get all tool IDs without loading full data.
87898791
87908792 Args:
8793+ q (str): Search query to filter tools by name, ID, or description
87918794 include_inactive (bool): Whether to include inactive tools in the results
87928795 gateway_id (Optional[str]): Filter by gateway ID(s), comma-separated. Accepts the literal value 'null' to indicate NULL gateway_id (local tools).
87938796 team_id (Optional[str]): Filter by team ID.
8797+ include_public (bool): Whether to include all platform-public tools when filtering by team.
87948798 db (Session): Database session dependency
87958799 user: Current user making the request
87968800
@@ -8807,6 +8811,21 @@ async def admin_get_all_tool_ids(
88078811 if not include_inactive:
88088812 query = query.where(DbTool.enabled.is_(True))
88098813
8814+ # Apply search filter if provided
8815+ if q:
8816+ search_query = _normalize_search_query(q)
8817+ if search_query:
8818+ search_conditions = [
8819+ _like_contains(func.lower(DbTool.id), search_query),
8820+ _like_contains(func.lower(DbTool.original_name), search_query),
8821+ _like_contains(func.lower(coalesce(DbTool.display_name, "")), search_query),
8822+ _like_contains(func.lower(coalesce(DbTool.custom_name, "")), search_query),
8823+ _like_contains(func.lower(coalesce(DbTool.description, "")), search_query),
8824+ _like_contains(func.lower(coalesce(DbTool.url, "")), search_query),
8825+ ]
8826+ query = query.where(or_(*search_conditions))
8827+ LOGGER.debug(f"Filtering tool IDs by search query: {search_query}")
8828+
88108829 # Apply optional gateway/server scoping (comma-separated ids). Accepts the
88118830 # literal value 'null' to indicate NULL gateway_id (local tools).
88128831 if gateway_id:
@@ -8825,22 +8844,19 @@ async def admin_get_all_tool_ids(
88258844 LOGGER.debug(f"Filtering tools by gateway IDs: {non_null_ids}")
88268845
88278846 # Build access conditions
8828- # When team_id is specified, show items from that team plus all platform-public tools
8829- # (visibility="public") so the "Select All" count and payload match what is actually
8830- # visible in the edit UI. Public visibility is platform-wide regardless of team ownership.
8847+ # When team_id is specified, show items from that team; optionally include
8848+ # platform-public items when include_public is set (mirrors the partial endpoint).
88318849 # Otherwise, show all accessible items (All Teams view).
88328850 if team_id:
88338851 if team_id in team_ids:
8834- # Apply visibility check: team/public resources + user's own resources (including private)
8835- # Also include all platform-public tools so they can be associated with team-owned
8836- # virtual servers.
88378852 team_access = [
88388853 and_(DbTool.team_id == team_id, DbTool.visibility.in_(["team", "public"])),
88398854 and_(DbTool.team_id == team_id, DbTool.owner_email == user_email),
8840- DbTool.visibility == "public",
88418855 ]
8856+ if include_public:
8857+ team_access.append(DbTool.visibility == "public")
88428858 query = query.where(or_(*team_access))
8843- LOGGER.debug(f"Filtering tool IDs by team_id: {team_id}")
8859+ LOGGER.debug(f"Filtering tool IDs by team_id: {team_id}{' (include_public)' if include_public else ''} ")
88448860 else:
88458861 LOGGER.warning(f"User {user_email} attempted to filter tool IDs by team {team_id} but is not a member")
88468862 query = query.where(false())
@@ -10020,9 +10036,11 @@ async def admin_resources_partial_html(
1002010036@admin_router.get("/prompts/ids", response_class=JSONResponse)
1002110037@require_permission("prompts.read", allow_admin_bypass=False)
1002210038async def admin_get_all_prompt_ids(
10039+ q: str = Query("", description="Search query"),
1002310040 include_inactive: bool = False,
1002410041 gateway_id: Optional[str] = Query(None, description="Filter by gateway ID(s), comma-separated"),
1002510042 team_id: Optional[str] = Depends(_validated_team_id_param),
10043+ include_public: bool = False,
1002610044 db: Session = Depends(get_db),
1002710045 user=Depends(get_current_user_with_permissions),
1002810046):
@@ -10032,9 +10050,11 @@ async def admin_get_all_prompt_ids(
1003210050 of prompts the requesting user can access (owner, team, or public).
1003310051
1003410052 Args:
10053+ q (str): Search query to filter prompts by name or description.
1003510054 include_inactive (bool): When True include prompts that are inactive.
1003610055 gateway_id (Optional[str]): Filter by gateway ID(s), comma-separated. Accepts the literal value 'null' to indicate NULL gateway_id (local prompts).
1003710056 team_id (Optional[str]): Filter by team ID.
10057+ include_public (bool): Whether to include all platform-public prompts when filtering by team.
1003810058 db (Session): Database session (injected dependency).
1003910059 user: Authenticated user object from dependency injection.
1004010060
@@ -10048,6 +10068,22 @@ async def admin_get_all_prompt_ids(
1004810068
1004910069 query = select(DbPrompt.id)
1005010070
10071+ if not include_inactive:
10072+ query = query.where(DbPrompt.enabled.is_(True))
10073+
10074+ # Apply search filter if provided
10075+ if q:
10076+ search_query = _normalize_search_query(q)
10077+ if search_query:
10078+ search_conditions = [
10079+ _like_contains(func.lower(DbPrompt.id), search_query),
10080+ _like_contains(func.lower(DbPrompt.original_name), search_query),
10081+ _like_contains(func.lower(coalesce(DbPrompt.display_name, "")), search_query),
10082+ _like_contains(func.lower(coalesce(DbPrompt.description, "")), search_query),
10083+ ]
10084+ query = query.where(or_(*search_conditions))
10085+ LOGGER.debug(f"Filtering prompt IDs by search query: {search_query}")
10086+
1005110087 # Apply optional gateway/server scoping
1005210088 if gateway_id:
1005310089 gateway_ids = [gid.strip() for gid in gateway_id.split(",") if gid.strip()]
@@ -10064,27 +10100,20 @@ async def admin_get_all_prompt_ids(
1006410100 query = query.where(DbPrompt.gateway_id.in_(non_null_ids))
1006510101 LOGGER.debug(f"Filtering prompts by gateway IDs: {non_null_ids}")
1006610102
10067- if not include_inactive:
10068- query = query.where(DbPrompt.enabled.is_(True))
10069-
1007010103 # Build access conditions
10071- # When team_id is specified, show items from that team plus all platform-public prompts
10072- # (visibility="public") so the "Select All" count and payload match what is actually
10073- # visible in the edit UI. Public visibility is platform-wide regardless of team ownership.
10104+ # When team_id is specified, show items from that team; optionally include
10105+ # platform-public items when include_public is set (mirrors the partial endpoint).
1007410106 # Otherwise, show all accessible items (All Teams view).
1007510107 if team_id:
10076- # Team-specific view: show prompts from the specified team plus platform-public prompts
1007710108 if team_id in team_ids:
10078- # Apply visibility check: team/public resources + user's own resources (including private)
10079- # Also include all platform-public prompts so they can be associated with team-owned
10080- # virtual servers.
1008110109 team_access = [
1008210110 and_(DbPrompt.team_id == team_id, DbPrompt.visibility.in_(["team", "public"])),
1008310111 and_(DbPrompt.team_id == team_id, DbPrompt.owner_email == user_email),
10084- DbPrompt.visibility == "public",
1008510112 ]
10113+ if include_public:
10114+ team_access.append(DbPrompt.visibility == "public")
1008610115 query = query.where(or_(*team_access))
10087- LOGGER.debug(f"Filtering prompt IDs by team_id: {team_id}")
10116+ LOGGER.debug(f"Filtering prompt IDs by team_id: {team_id}{' (include_public)' if include_public else ''} ")
1008810117 else:
1008910118 # User is not a member of this team, return no results using SQLAlchemy's false()
1009010119 LOGGER.warning(f"User {user_email} attempted to filter prompt IDs by team {team_id} but is not a member")
@@ -10105,9 +10134,11 @@ async def admin_get_all_prompt_ids(
1010510134@admin_router.get("/resources/ids", response_class=JSONResponse)
1010610135@require_permission("resources.read", allow_admin_bypass=False)
1010710136async def admin_get_all_resource_ids(
10137+ q: str = Query("", description="Search query"),
1010810138 include_inactive: bool = False,
1010910139 gateway_id: Optional[str] = Query(None, description="Filter by gateway ID(s), comma-separated"),
1011010140 team_id: Optional[str] = Depends(_validated_team_id_param),
10141+ include_public: bool = False,
1011110142 db: Session = Depends(get_db),
1011210143 user=Depends(get_current_user_with_permissions),
1011310144):
@@ -10117,9 +10148,11 @@ async def admin_get_all_resource_ids(
1011710148 of resources the requesting user can access (owner, team, or public).
1011810149
1011910150 Args:
10151+ q (str): Search query to filter resources by name, URI, or description.
1012010152 include_inactive (bool): Whether to include inactive resources in the results.
1012110153 gateway_id (Optional[str]): Filter by gateway ID(s), comma-separated. Accepts the literal value 'null' to indicate NULL gateway_id (local resources).
1012210154 team_id (Optional[str]): Filter by team ID.
10155+ include_public (bool): Whether to include all platform-public resources when filtering by team.
1012310156 db (Session): Database session dependency.
1012410157 user: Authenticated user object from dependency injection.
1012510158
@@ -10133,6 +10166,22 @@ async def admin_get_all_resource_ids(
1013310166
1013410167 query = select(DbResource.id)
1013510168
10169+ if not include_inactive:
10170+ query = query.where(DbResource.enabled.is_(True))
10171+
10172+ # Apply search filter if provided
10173+ if q:
10174+ search_query = _normalize_search_query(q)
10175+ if search_query:
10176+ search_conditions = [
10177+ _like_contains(func.lower(DbResource.id), search_query),
10178+ _like_contains(func.lower(DbResource.name), search_query),
10179+ _like_contains(func.lower(coalesce(DbResource.uri, "")), search_query),
10180+ _like_contains(func.lower(coalesce(DbResource.description, "")), search_query),
10181+ ]
10182+ query = query.where(or_(*search_conditions))
10183+ LOGGER.debug(f"Filtering resource IDs by search query: {search_query}")
10184+
1013610185 # Apply optional gateway/server scoping
1013710186 if gateway_id:
1013810187 gateway_ids = [gid.strip() for gid in gateway_id.split(",") if gid.strip()]
@@ -10149,27 +10198,20 @@ async def admin_get_all_resource_ids(
1014910198 query = query.where(DbResource.gateway_id.in_(non_null_ids))
1015010199 LOGGER.debug(f"Filtering resources by gateway IDs: {non_null_ids}")
1015110200
10152- if not include_inactive:
10153- query = query.where(DbResource.enabled.is_(True))
10154-
1015510201 # Build access conditions
10156- # When team_id is specified, show items from that team plus all platform-public resources
10157- # (visibility="public") so the "Select All" count and payload match what is actually
10158- # visible in the edit UI. Public visibility is platform-wide regardless of team ownership.
10202+ # When team_id is specified, show items from that team; optionally include
10203+ # platform-public items when include_public is set (mirrors the partial endpoint).
1015910204 # Otherwise, show all accessible items (All Teams view).
1016010205 if team_id:
10161- # Team-specific view: show resources from the specified team plus platform-public resources
1016210206 if team_id in team_ids:
10163- # Apply visibility check: team/public resources + user's own resources (including private)
10164- # Also include all platform-public resources so they can be associated with team-owned
10165- # virtual servers.
1016610207 team_access = [
1016710208 and_(DbResource.team_id == team_id, DbResource.visibility.in_(["team", "public"])),
1016810209 and_(DbResource.team_id == team_id, DbResource.owner_email == user_email),
10169- DbResource.visibility == "public",
1017010210 ]
10211+ if include_public:
10212+ team_access.append(DbResource.visibility == "public")
1017110213 query = query.where(or_(*team_access))
10172- LOGGER.debug(f"Filtering resource IDs by team_id: {team_id}")
10214+ LOGGER.debug(f"Filtering resource IDs by team_id: {team_id}{' (include_public)' if include_public else ''} ")
1017310215 else:
1017410216 # User is not a member of this team, return no results using SQLAlchemy's false()
1017510217 LOGGER.warning(f"User {user_email} attempted to filter resource IDs by team {team_id} but is not a member")
0 commit comments