Files
AgentCompany/src/renderer/components/connectors.tsx
T
ZacharyZhang-NY 7fdd3c16bf feat(renderer): rewrite providers UI on pi-mono catalog shape
Onboarding ProvidersStep now reads the 26-entry CONNECTOR_CATALOG and
renders featured connectors (claude-pro, openai-codex, anthropic, openai,
amazon-bedrock) up front with a collapsible advanced list for the
remaining 21. Each auth kind gets a dedicated card component: OAuth
button flow, inline API-key form, and a cloud deep-link to Settings.
Delete legacy Claude/Codex/Gemini hardcoded cards and the compatible-API
slot rotation. Swap ModelManagement Settings panel for the new
ProvidersPanel driven by credentialsList IPC.
2026-04-17 02:16:35 -04:00

104 lines
3.9 KiB
TypeScript

import { useEffect, useState } from "react";
import type { ConnectorRecord } from "@shared/types";
import { findConnectorCatalogEntry } from "@shared/connector-catalog";
import type { CredentialSummary } from "@shared/contracts/schemas-credentials";
import { InlineNotice, StatusPill } from "./ui";
const AUTH_KIND_LABEL: Record<string, string> = {
oauth: "OAuth",
api_key: "API key",
aws: "AWS",
azure: "Azure",
gcp_adc: "Google Vertex (ADC)",
};
/**
* Legacy connector detail view. Real configuration happens in
* Settings → Providers. Here we only surface catalog metadata and the current
* credential status pulled from the pi-mono credential store.
*/
export function ConnectorEditor({
connector,
}: {
connector: ConnectorRecord;
onSaved: () => Promise<void>;
}) {
const [credential, setCredential] = useState<CredentialSummary | null>(null);
const [error, setError] = useState<string | null>(null);
const catalog = findConnectorCatalogEntry(connector.id);
useEffect(() => {
const desktop = window.agentCompany;
if (!desktop) return;
let cancelled = false;
const refresh = async () => {
const result = await desktop.listCredentials();
if (cancelled) return;
if (!result.ok) {
setError(result.error.message);
return;
}
setCredential(result.data.find((row) => row.connectorId === connector.id) ?? null);
};
void refresh();
const unsubscribe = desktop.subscribe((event) => {
if (event.type !== "credentials-changed") return;
void refresh();
});
return () => {
cancelled = true;
unsubscribe();
};
}, [connector.id]);
return (
<div className="grid gap-4">
{error ? <InlineNotice message={error} /> : null}
<div className="grid gap-4 md:grid-cols-2">
<div>
<div className="mb-1.5 text-[12px] font-medium text-muted-foreground">Status</div>
<div className="flex items-center gap-3">
<StatusPill status={connector.status} />
<span className="text-[12px] text-muted-foreground">
{credential ? credential.status : "not configured"}
</span>
</div>
</div>
<div>
<div className="mb-1.5 text-[12px] font-medium text-muted-foreground">Auth</div>
<div className="text-[13px] text-foreground">
{catalog ? AUTH_KIND_LABEL[catalog.auth.type] ?? catalog.auth.type : "Unknown"}
</div>
</div>
</div>
<div>
<div className="mb-1.5 text-[12px] font-medium text-muted-foreground">Provider id</div>
<div className="font-mono text-[12px] text-foreground">{catalog?.provider ?? connector.id}</div>
</div>
{catalog?.description ? (
<div>
<div className="mb-1.5 text-[12px] font-medium text-muted-foreground">Description</div>
<div className="text-[12px] leading-relaxed text-muted-foreground">{catalog.description}</div>
</div>
) : null}
{catalog?.notes ? (
<div>
<div className="mb-1.5 text-[12px] font-medium text-muted-foreground">Notes</div>
<div className="text-[12px] leading-relaxed text-muted-foreground">{catalog.notes}</div>
</div>
) : null}
<div className="rounded-lg border border-border bg-muted px-4 py-3 text-[12px] leading-relaxed text-muted-foreground">
Manage credentials in Settings → Providers. Status and OAuth flows are handled by the pi-mono credential store.
</div>
{credential?.lastError ? (
<div className="rounded-lg border border-border bg-muted px-4 py-3 text-[12px] leading-relaxed text-muted-foreground">
<div className="mb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
Latest credential error
</div>
<div>{credential.lastError}</div>
</div>
) : null}
</div>
);
}