Compare commits

...

1 Commits

Author SHA1 Message Date
6acd85ea70 fix(web): correct Add Provider form to match fleet-settings DTO
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
2026-03-01 14:00:44 -06:00
3 changed files with 40 additions and 40 deletions

View File

@@ -85,12 +85,16 @@ const INITIAL_FORM: ProviderFormState = {
isActive: true, isActive: true,
}; };
function mapProviderTypeToApi(type: string): "ollama" | "openai" | "claude" { function buildProviderName(displayName: string, type: string): string {
if (type === "ollama" || type === "claude") { const slug = displayName
return type; .trim()
} .toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+/, "")
.replace(/-+$/, "");
return "openai"; const candidate = `${type}-${slug.length > 0 ? slug : "provider"}`;
return candidate.slice(0, 100);
} }
function getErrorMessage(error: unknown, fallback: string): string { function getErrorMessage(error: unknown, fallback: string): string {
@@ -299,27 +303,24 @@ export default function ProvidersSettingsPage(): ReactElement {
await updateFleetProvider(editingProvider.id, updatePayload); await updateFleetProvider(editingProvider.id, updatePayload);
setSuccessMessage(`Updated provider "${displayName}".`); setSuccessMessage(`Updated provider "${displayName}".`);
} else { } else {
const config: CreateFleetProviderRequest["config"] = {}; const createPayload: CreateFleetProviderRequest = {
name: buildProviderName(displayName, form.type),
displayName,
type: form.type,
};
if (baseUrl.length > 0) { if (baseUrl.length > 0) {
config.endpoint = baseUrl; createPayload.baseUrl = baseUrl;
} }
if (apiKey.length > 0) { if (apiKey.length > 0) {
config.apiKey = apiKey; createPayload.apiKey = apiKey;
} }
if (models.length > 0) { if (providerModels.length > 0) {
config.models = models; createPayload.models = providerModels;
} }
const createPayload: CreateFleetProviderRequest = {
displayName,
providerType: mapProviderTypeToApi(form.type),
config,
isEnabled: form.isActive,
};
await createFleetProvider(createPayload); await createFleetProvider(createPayload);
setSuccessMessage(`Added provider "${displayName}".`); setSuccessMessage(`Added provider "${displayName}".`);
} }

View File

@@ -34,25 +34,27 @@ describe("createFleetProvider", (): void => {
vi.mocked(client.apiPost).mockResolvedValueOnce({ id: "provider-1" } as never); vi.mocked(client.apiPost).mockResolvedValueOnce({ id: "provider-1" } as never);
await createFleetProvider({ await createFleetProvider({
providerType: "openai", name: "openai-main",
displayName: "OpenAI Main", displayName: "OpenAI Main",
config: { type: "openai",
endpoint: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
apiKey: "sk-test", apiKey: "sk-test",
models: ["gpt-4.1-mini", "gpt-4o-mini"], models: [
}, { id: "gpt-4.1-mini", name: "gpt-4.1-mini" },
isEnabled: true, { id: "gpt-4o-mini", name: "gpt-4o-mini" },
],
}); });
expect(client.apiPost).toHaveBeenCalledWith("/api/fleet-settings/providers", { expect(client.apiPost).toHaveBeenCalledWith("/api/fleet-settings/providers", {
providerType: "openai", name: "openai-main",
displayName: "OpenAI Main", displayName: "OpenAI Main",
config: { type: "openai",
endpoint: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
apiKey: "sk-test", apiKey: "sk-test",
models: ["gpt-4.1-mini", "gpt-4o-mini"], models: [
}, { id: "gpt-4.1-mini", name: "gpt-4.1-mini" },
isEnabled: true, { id: "gpt-4o-mini", name: "gpt-4o-mini" },
],
}); });
}); });
}); });

View File

@@ -16,16 +16,13 @@ export interface FleetProvider {
} }
export interface CreateFleetProviderRequest { export interface CreateFleetProviderRequest {
providerType: "ollama" | "openai" | "claude"; name: string;
displayName: string; displayName: string;
config: { type: string;
endpoint?: string; baseUrl?: string;
apiKey?: string; apiKey?: string;
models?: string[]; apiType?: string;
timeout?: number; models?: FleetProviderModel[];
};
isDefault?: boolean;
isEnabled?: boolean;
} }
export interface UpdateFleetProviderRequest { export interface UpdateFleetProviderRequest {