Skip to content
Closed
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
17 changes: 16 additions & 1 deletion react/src/pages/AdminServingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import EndpointList from '../components/EndpointList';
import { useWebUINavigate } from '../hooks';
import { useCurrentUserRole } from '../hooks/backendai';
import { useBAIPaginationOptionStateOnSearchParamLegacy } from '../hooks/reactPaginationQueryOptions';
import { useCurrentProjectValue } from '../hooks/useCurrentProject';
import { useEffectiveAdminRole } from '../hooks/useCurrentUserProjectRoles';
import { Skeleton } from 'antd';
import {
BAICard,
Expand All @@ -32,6 +34,16 @@ const AdminModelCardListPage = React.lazy(
const ServingTabContent: React.FC = () => {
'use memo';
const { t } = useTranslation();
const effectiveRole = useEffectiveAdminRole();
const currentProject = useCurrentProjectValue();

// Path B (interim): legacy `endpoint_list(project: UUID)` for project admins.
// Domain-admin scope cannot be precisely matched via the current schema —
// `endpoint_list` has no `scope_id` argument and there is no `endpoint_nodes`
// Relay node. Leave unfiltered for domainAdmin until backend support lands.
// TODO(needs-backend): FR-2313 — domain-scope RBAC for endpoint_list
const projectFilter =
effectiveRole === 'projectAdmin' ? (currentProject.id ?? null) : null;
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

projectFilter uses null for the “no project filter” case, which means $project is always sent to GraphQL as an explicit null. Elsewhere in the codebase, endpoint_list optional project scoping is typically omitted by leaving the variable undefined (e.g., react/src/components/Chat/EndpointSelect.tsx:137-140 passes only {limit: 10}), which avoids any backend behavior differences between “arg omitted” vs “arg provided as null”. Consider changing the non-projectAdmin branch to undefined (and keeping the variable optional) so Relay omits $project entirely when unscoped.

Suggested change
effectiveRole === 'projectAdmin' ? (currentProject.id ?? null) : null;
effectiveRole === 'projectAdmin' ? (currentProject.id ?? undefined) : undefined;

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +46
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For effectiveRole === 'projectAdmin', projectFilter falls back to null when currentProject.id is missing. That would result in an unscoped endpoint_list query for a project admin, undermining the intended “scope by project” behavior. Consider blocking the query (or returning an empty state) until currentProject.id is available, or keep projectFilter as undefined/throw when it’s unexpectedly absent for project admins.

Copilot uses AI. Check for mistakes.

const [queryParam, setQueryParam] = useQueryStates(
{
Expand Down Expand Up @@ -71,8 +83,9 @@ const ServingTabContent: React.FC = () => {
limit: baiPaginationOption.limit,
filter: mergeFilterValues([lifecycleStageFilter, queryParam.filter]),
order: queryParam.order,
project: projectFilter,
}),
[baiPaginationOption, lifecycleStageFilter, queryParam],
[baiPaginationOption, lifecycleStageFilter, queryParam, projectFilter],
);

const deferredQueryVariables = useDeferredValue(queryVariables);
Expand All @@ -85,12 +98,14 @@ const ServingTabContent: React.FC = () => {
$limit: Int!
$filter: String
$order: String
$project: UUID
) {
endpoint_list(
offset: $offset
limit: $limit
filter: $filter
order: $order
project: $project
) {
total_count
items {
Expand Down
Loading