feat(FN-3059): align provider metadata and documentation
Merged feat(FN-3059) which aligns provider metadata and documentation across the codebase, updating README and getting-started docs plus refinements to the CustomProviderForm and ProviderIcon dashboard components. Fusion-Task-Id: FN-3059
This commit is contained in:
@@ -2,7 +2,7 @@ import { useMemo, useState } from "react";
|
||||
import type { CustomProviderConfig, CustomProviderModelInput } from "../api";
|
||||
import "./CustomProviderForm.css";
|
||||
|
||||
// Keep in sync with BUILT_IN_PROVIDER_IDS in register-custom-provider-routes.ts
|
||||
// Reserved built-in IDs (including hidden/deprecated aliases) to prevent custom-provider collisions.
|
||||
export const BUILT_IN_PROVIDER_IDS = new Set<string>([
|
||||
"anthropic", "claude-cli", "pi-claude-cli", "openai", "openai-codex", "google", "gemini", "google-antigravity",
|
||||
"antigravity", "google-vertex", "vertex", "google-cloud-code", "cloud-code", "google-gemini-cli", "google-generative-ai",
|
||||
|
||||
@@ -26,6 +26,7 @@ import { DroidCliProviderCard } from "./DroidCliProviderCard";
|
||||
import { LoginInstructions } from "./LoginInstructions";
|
||||
import { CustomProviderForm } from "./CustomProviderForm";
|
||||
import { appendTokenQuery } from "../auth";
|
||||
import { filterVisibleOnboardingAndSettingsProviders } from "./providerVisibility";
|
||||
|
||||
const mapLegacyCustomProviderToConfig = (
|
||||
provider: CustomProvider | CustomProviderConfig,
|
||||
@@ -736,12 +737,13 @@ export function ModelOnboardingModal({
|
||||
const loadAuthStatus = useCallback(async () => {
|
||||
try {
|
||||
const { providers, ghCli } = await fetchAuthStatus();
|
||||
setAuthProviders(providers);
|
||||
const visibleProviders = filterVisibleOnboardingAndSettingsProviders(providers);
|
||||
setAuthProviders(visibleProviders);
|
||||
setGhCliStatus(ghCli);
|
||||
setLoginInstructions((prev) => {
|
||||
const next: Record<string, string> = {};
|
||||
for (const [providerId, instructions] of Object.entries(prev)) {
|
||||
const provider = providers.find((candidate) => candidate.id === providerId);
|
||||
const provider = visibleProviders.find((candidate) => candidate.id === providerId);
|
||||
if (provider && !provider.authenticated && provider.loginInProgress) {
|
||||
next[providerId] = instructions;
|
||||
}
|
||||
@@ -755,7 +757,7 @@ export function ModelOnboardingModal({
|
||||
if (outcome !== "pending") {
|
||||
continue;
|
||||
}
|
||||
const provider = providers.find((candidate) => candidate.id === providerId);
|
||||
const provider = visibleProviders.find((candidate) => candidate.id === providerId);
|
||||
if (!provider?.loginInProgress) {
|
||||
delete next[providerId];
|
||||
changed = true;
|
||||
@@ -766,7 +768,7 @@ export function ModelOnboardingModal({
|
||||
// Remove from skippedProviders when a provider becomes authenticated
|
||||
setSkippedProviders((prev) => {
|
||||
const updated = { ...prev };
|
||||
for (const p of providers) {
|
||||
for (const p of visibleProviders) {
|
||||
if (p.authenticated && updated[p.id]) {
|
||||
delete updated[p.id];
|
||||
}
|
||||
@@ -1129,9 +1131,10 @@ export function ModelOnboardingModal({
|
||||
|
||||
try {
|
||||
const { providers, ghCli } = await fetchAuthStatus();
|
||||
setAuthProviders(providers);
|
||||
const visibleProviders = filterVisibleOnboardingAndSettingsProviders(providers);
|
||||
setAuthProviders(visibleProviders);
|
||||
setGhCliStatus(ghCli);
|
||||
const provider = providers.find((p) => p.id === providerId);
|
||||
const provider = visibleProviders.find((p) => p.id === providerId);
|
||||
if (provider?.authenticated) {
|
||||
if (pollIntervalRef.current) {
|
||||
clearInterval(pollIntervalRef.current);
|
||||
|
||||
@@ -659,12 +659,14 @@ const providerConfig: Record<
|
||||
|
||||
google: { component: GeminiIcon, color: "var(--provider-gemini)" },
|
||||
gemini: { component: GeminiIcon, color: "var(--provider-gemini)" }, // Gemini alias family
|
||||
// Deprecated upstream in pi-coding-agent 0.71+, retained for legacy usage/auth history rendering.
|
||||
"google-antigravity": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini" },
|
||||
antigravity: { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini" },
|
||||
"google-vertex": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Vertex AI" },
|
||||
vertex: { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Vertex AI" },
|
||||
"google-cloud-code": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Cloud Code" },
|
||||
"cloud-code": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Cloud Code" },
|
||||
// Deprecated upstream in pi-coding-agent 0.71+, retained for legacy usage/auth history rendering.
|
||||
"google-gemini-cli": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini CLI" },
|
||||
"google-generative-ai": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Generative AI" },
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import { appendTokenQuery } from "../auth";
|
||||
import { useConfirm } from "../hooks/useConfirm";
|
||||
import { useNodes } from "../hooks/useNodes";
|
||||
import { NodeHealthDot } from "./NodeHealthDot";
|
||||
import { filterVisibleOnboardingAndSettingsProviders } from "./providerVisibility";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GitHub star count — fetched once per session, cached in localStorage (1 h).
|
||||
@@ -654,11 +655,12 @@ export function SettingsModal({
|
||||
const loadAuthStatus = useCallback(async () => {
|
||||
try {
|
||||
const { providers } = await fetchAuthStatus();
|
||||
setAuthProviders(providers);
|
||||
const visibleProviders = filterVisibleOnboardingAndSettingsProviders(providers);
|
||||
setAuthProviders(visibleProviders);
|
||||
setLoginInstructions((prev) => {
|
||||
const next: Record<string, string> = {};
|
||||
for (const [providerId, instructions] of Object.entries(prev)) {
|
||||
const provider = providers.find((candidate) => candidate.id === providerId);
|
||||
const provider = visibleProviders.find((candidate) => candidate.id === providerId);
|
||||
if (provider && !provider.authenticated) {
|
||||
next[providerId] = instructions;
|
||||
}
|
||||
@@ -910,8 +912,9 @@ export function SettingsModal({
|
||||
pollIntervalRef.current = setInterval(async () => {
|
||||
try {
|
||||
const { providers } = await fetchAuthStatus();
|
||||
setAuthProviders(providers);
|
||||
const provider = providers.find((p) => p.id === providerId);
|
||||
const visibleProviders = filterVisibleOnboardingAndSettingsProviders(providers);
|
||||
setAuthProviders(visibleProviders);
|
||||
const provider = visibleProviders.find((p) => p.id === providerId);
|
||||
if (provider?.authenticated) {
|
||||
if (pollIntervalRef.current) {
|
||||
clearInterval(pollIntervalRef.current);
|
||||
|
||||
@@ -249,6 +249,26 @@ describe("ModelOnboardingModal", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("hides deprecated google CLI and antigravity providers while keeping supported Google/Gemini entries", async () => {
|
||||
mockFetchAuthStatus.mockResolvedValueOnce({
|
||||
providers: [
|
||||
{ id: "google", name: "Google", authenticated: false, type: "api_key" },
|
||||
{ id: "gemini", name: "Gemini", authenticated: false, type: "api_key" },
|
||||
{ id: "google-antigravity", name: "Google Antigravity", authenticated: false, type: "oauth" },
|
||||
{ id: "antigravity", name: "Antigravity", authenticated: false, type: "oauth" },
|
||||
{ id: "google-gemini-cli", name: "Google Gemini CLI", authenticated: false, type: "cli" },
|
||||
],
|
||||
});
|
||||
|
||||
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={vi.fn()} projectId="proj_123" />);
|
||||
|
||||
expect(await screen.findByTestId("onboarding-provider-card-google")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("onboarding-provider-card-gemini")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("onboarding-provider-card-google-antigravity")).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId("onboarding-provider-card-antigravity")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Google Gemini CLI")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows Back and Next buttons on middle steps", async () => {
|
||||
mockFetchAuthStatus.mockResolvedValueOnce({
|
||||
providers: [
|
||||
|
||||
@@ -827,6 +827,27 @@ describe("SettingsModal", () => {
|
||||
expect(screen.getByTestId("auth-status-openai")).toHaveTextContent("✗ Not connected");
|
||||
});
|
||||
|
||||
it("hides deprecated Google CLI and antigravity auth providers", async () => {
|
||||
mockFetchAuthStatus.mockResolvedValueOnce({
|
||||
providers: [
|
||||
{ id: "google", name: "Google", authenticated: false, type: "api_key" },
|
||||
{ id: "gemini", name: "Gemini", authenticated: false, type: "api_key" },
|
||||
{ id: "google-antigravity", name: "Google Antigravity", authenticated: false, type: "oauth" },
|
||||
{ id: "antigravity", name: "Antigravity", authenticated: false, type: "oauth" },
|
||||
{ id: "google-gemini-cli", name: "Google Gemini CLI", authenticated: false, type: "cli" },
|
||||
],
|
||||
});
|
||||
|
||||
renderModal();
|
||||
await waitForSettingsModalReady();
|
||||
|
||||
expect(screen.getByTestId("auth-provider-icon-google")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("auth-provider-icon-gemini")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("auth-provider-icon-google-antigravity")).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId("auth-provider-icon-antigravity")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Google Gemini CLI")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("scrolls settings content to top after OAuth login succeeds", async () => {
|
||||
const openSpy = vi.spyOn(window, "open").mockImplementation(() => null);
|
||||
mockLoginProvider.mockResolvedValue({ url: "https://example.com/auth", instructions: "" });
|
||||
|
||||
17
packages/dashboard/app/components/providerVisibility.ts
Normal file
17
packages/dashboard/app/components/providerVisibility.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const HIDDEN_ONBOARDING_AND_SETTINGS_PROVIDER_IDS = new Set([
|
||||
"google-antigravity",
|
||||
"antigravity",
|
||||
"google-gemini-cli",
|
||||
]);
|
||||
|
||||
export function isProviderVisibleInOnboardingAndSettings(providerId: string): boolean {
|
||||
return !HIDDEN_ONBOARDING_AND_SETTINGS_PROVIDER_IDS.has(providerId);
|
||||
}
|
||||
|
||||
export function filterVisibleOnboardingAndSettingsProviders<T extends { id: string }>(
|
||||
providers: T[],
|
||||
): T[] {
|
||||
return providers.filter((provider) => isProviderVisibleInOnboardingAndSettings(provider.id));
|
||||
}
|
||||
|
||||
export { HIDDEN_ONBOARDING_AND_SETTINGS_PROVIDER_IDS };
|
||||
Reference in New Issue
Block a user