diff --git a/backend/internal/handler/admin/dashboard_handler.go b/backend/internal/handler/admin/dashboard_handler.go index b42b395d33..8f55fb4165 100644 --- a/backend/internal/handler/admin/dashboard_handler.go +++ b/backend/internal/handler/admin/dashboard_handler.go @@ -657,11 +657,14 @@ func (h *DashboardHandler) GetUserBreakdown(c *gin.Context) { dim.AccountID = id } } - if v := c.Query("request_type"); v != "" { - if rt, err := strconv.ParseInt(v, 10, 16); err == nil { - rtVal := int16(rt) - dim.RequestType = &rtVal + if v := strings.TrimSpace(c.Query("request_type")); v != "" { + parsed, err := service.ParseUsageRequestType(v) + if err != nil { + response.BadRequest(c, err.Error()) + return } + rtVal := int16(parsed) + dim.RequestType = &rtVal } if v := c.Query("stream"); v != "" { if s, err := strconv.ParseBool(v); err == nil { diff --git a/backend/internal/handler/admin/dashboard_handler_user_breakdown_test.go b/backend/internal/handler/admin/dashboard_handler_user_breakdown_test.go index 3065eee3c4..2381364a94 100644 --- a/backend/internal/handler/admin/dashboard_handler_user_breakdown_test.go +++ b/backend/internal/handler/admin/dashboard_handler_user_breakdown_test.go @@ -241,3 +241,42 @@ func TestGetUserBreakdown_NoFilters(t *testing.T) { require.Empty(t, repo.capturedDim.Model) require.Empty(t, repo.capturedDim.Endpoint) } + +func TestGetUserBreakdown_RequestTypeStringFilter(t *testing.T) { + cases := []struct { + name string + value string + want int16 + }{ + {"ws_v2", "ws_v2", int16(service.RequestTypeWSV2)}, + {"stream", "stream", int16(service.RequestTypeStream)}, + {"sync", "sync", int16(service.RequestTypeSync)}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + repo := &userBreakdownRepoCapture{} + router := newUserBreakdownRouter(repo) + + req := httptest.NewRequest(http.MethodGet, + "/admin/dashboard/user-breakdown?start_date=2026-03-01&end_date=2026-03-16&request_type="+tc.value, nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, req) + + require.Equal(t, http.StatusOK, w.Code) + require.NotNil(t, repo.capturedDim.RequestType, "request_type=%s should set filter", tc.value) + require.Equal(t, tc.want, *repo.capturedDim.RequestType) + }) + } +} + +func TestGetUserBreakdown_InvalidRequestType(t *testing.T) { + repo := &userBreakdownRepoCapture{} + router := newUserBreakdownRouter(repo) + + req := httptest.NewRequest(http.MethodGet, + "/admin/dashboard/user-breakdown?start_date=2026-03-01&end_date=2026-03-16&request_type=bogus", nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, req) + + require.Equal(t, http.StatusBadRequest, w.Code) +} diff --git a/frontend/src/api/admin/dashboard.ts b/frontend/src/api/admin/dashboard.ts index 97c16aa362..ae20d33f8e 100644 --- a/frontend/src/api/admin/dashboard.ts +++ b/frontend/src/api/admin/dashboard.ts @@ -173,7 +173,7 @@ export interface UserBreakdownParams { user_id?: number api_key_id?: number account_id?: number - request_type?: number + request_type?: UsageRequestType stream?: boolean billing_type?: number | null }