diff --git a/backend/internal/api/server_middleware.go b/backend/internal/api/server_middleware.go index 00b1fc3..64119c0 100644 --- a/backend/internal/api/server_middleware.go +++ b/backend/internal/api/server_middleware.go @@ -33,8 +33,8 @@ var corsExposedResponseHeaders = []string{ var corsExposedResponseHeadersJoined = strings.Join(corsExposedResponseHeaders, ", ") const ( - exampleAPIKeyManagementPath = "/management.html" - exampleAPIKeyManagementURL = "/management.html?safe-mode=configure" + exampleAPIKeyManagementPath = "/admin" + exampleAPIKeyManagementURL = "/admin?safe-mode=configure" ) func (s *Server) homeHeartbeatMiddleware() gin.HandlerFunc { @@ -45,7 +45,11 @@ func (s *Server) homeHeartbeatMiddleware() gin.HandlerFunc { } if c != nil && c.Request != nil { path := c.Request.URL.Path - if strings.HasPrefix(path, "/v0/management/") || path == "/v0/management" || strings.HasPrefix(path, "/v0/resource/plugins/") || path == "/management.html" { + if strings.HasPrefix(path, "/v0/management/") || + path == "/v0/management" || + strings.HasPrefix(path, "/v0/resource/plugins/") || + path == exampleAPIKeyManagementPath || + strings.HasPrefix(path, exampleAPIKeyManagementPath+"/") { c.Next() return } @@ -87,7 +91,7 @@ func (s *Server) exampleAPIKeySafeModeMiddleware() gin.HandlerFunc { c.Header("X-CPA-SAFE-MODE", "example-api-key") c.AbortWithStatusJSON(http.StatusForbidden, gin.H{ "error": "unsafe_example_api_key", - "message": "Proxy API endpoints are disabled because api-keys contains template values. Open /management.html?safe-mode=configure, update api-keys in Management, then retry.", + "message": "Proxy API endpoints are disabled because api-keys contains template values. Open /admin?safe-mode=configure, update api-keys in Management, then retry.", }) } } diff --git a/backend/internal/api/server_routes.go b/backend/internal/api/server_routes.go index e38e5b2..052f1e1 100644 --- a/backend/internal/api/server_routes.go +++ b/backend/internal/api/server_routes.go @@ -8,8 +8,6 @@ import ( "github.com/router-for-me/CLIProxyAPI/v7/sdk/api/handlers/openai" ) -const oauthCallbackSuccessHTML = `
You can close this window.
This window will close automatically in 5 seconds.
` - func (s *Server) setupRoutes() { healthzHandler := func(c *gin.Context) { if c.Request.Method == http.MethodHead { @@ -21,8 +19,10 @@ func (s *Server) setupRoutes() { s.engine.GET("/healthz", healthzHandler) s.engine.HEAD("/healthz", healthzHandler) - s.engine.GET("/management.html", s.serveManagementControlPanel) - s.engine.HEAD("/management.html", s.serveManagementControlPanel) + s.engine.GET("/admin", s.serveManagementControlPanel) + s.engine.HEAD("/admin", s.serveManagementControlPanel) + s.engine.GET("/admin/oauth-success", s.serveManagementControlPanel) + s.engine.HEAD("/admin/oauth-success", s.serveManagementControlPanel) s.engine.GET("/management-assets/*filepath", s.serveManagementAsset) s.engine.HEAD("/management-assets/*filepath", s.serveManagementAsset) @@ -59,7 +59,6 @@ func (s *Server) setupRoutes() { if state != "" { _, _ = managementHandlers.WriteOAuthCallbackFileForPendingSession(s.cfg.AuthDir, "codex", state, code, errStr) } - c.Header("Content-Type", "text/html; charset=utf-8") - c.String(http.StatusOK, oauthCallbackSuccessHTML) + c.Redirect(http.StatusSeeOther, "/admin/oauth-success") }) } diff --git a/backend/internal/api/server_test.go b/backend/internal/api/server_test.go index a5c87a1..2796b47 100644 --- a/backend/internal/api/server_test.go +++ b/backend/internal/api/server_test.go @@ -1529,7 +1529,7 @@ func TestHomeEnabledHidesManagementEndpointsAndControlPanel(t *testing.T) { }) t.Run("management control panel returns 404", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/management.html", nil) + req := httptest.NewRequest(http.MethodGet, "/admin", nil) rr := httptest.NewRecorder() server.engine.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { @@ -1566,27 +1566,27 @@ func TestExampleAPIKeySafeModeShowsWarningAndKeepsManagement(t *testing.T) { t.Fatalf("status = %d, want %d body=%s", rr.Code, http.StatusOK, rr.Body.String()) } body := rr.Body.String() - for _, want := range []string{"Example API key detected", "Open Management", `href="/management.html?safe-mode=configure"`} { + for _, want := range []string{"Example API key detected", "Open Management", `href="/admin?safe-mode=configure"`} { if !strings.Contains(body, want) { t.Fatalf("warning page missing %q: %s", want, body) } } }) - t.Run("management html defaults to warning page", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/management.html", nil) + t.Run("admin defaults to warning page", func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "/admin", nil) rr := httptest.NewRecorder() server.engine.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status = %d, want %d body=%s", rr.Code, http.StatusOK, rr.Body.String()) } if !strings.Contains(rr.Body.String(), "Example API key detected") { - t.Fatalf("management.html did not show warning page: %s", rr.Body.String()) + t.Fatalf("admin page did not show warning page: %s", rr.Body.String()) } }) - t.Run("management html head stops at warning page", func(t *testing.T) { - req := httptest.NewRequest(http.MethodHead, "/management.html", nil) + t.Run("admin head stops at warning page", func(t *testing.T) { + req := httptest.NewRequest(http.MethodHead, "/admin", nil) rr := httptest.NewRecorder() server.engine.ServeHTTP(rr, req) if rr.Code != http.StatusOK { @@ -1601,7 +1601,7 @@ func TestExampleAPIKeySafeModeShowsWarningAndKeepsManagement(t *testing.T) { }) t.Run("management button query opens control panel", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/management.html?safe-mode=configure", nil) + req := httptest.NewRequest(http.MethodGet, "/admin?safe-mode=configure", nil) rr := httptest.NewRecorder() server.engine.ServeHTTP(rr, req) if rr.Code != http.StatusOK { @@ -1643,7 +1643,7 @@ func TestExampleAPIKeySafeModeShowsWarningAndKeepsManagement(t *testing.T) { if strings.Contains(rr.Body.String(), "management_url") { t.Fatalf("body should not include management_url field: %s", rr.Body.String()) } - if !strings.Contains(rr.Body.String(), "/management.html?safe-mode=configure") { + if !strings.Contains(rr.Body.String(), "/admin?safe-mode=configure") { t.Fatalf("body missing management link in message: %s", rr.Body.String()) } if got := rr.Header().Get(internallogging.CPATraceIDHeader); got != "" { diff --git a/frontend/package.json b/frontend/package.json index 5c286c0..11f7bc3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz", + "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.32/methanium-ui.tgz", "lucide-react": "^0.542.0", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 85df36d..301b274 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -170,7 +170,7 @@ function Header({ loggedIn, onLogout }: { loggedIn: boolean; onLogout: () => voi size="sm" className="mr-1 shrink-0 px-[13px]! text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground" nativeButton={false} - render={} + render={} > {methaniumLogo &&