Fix provider health banner showing during onboarding (#372)

* disable provider health query until edited is true, set initial provider health cache to true when onboarding mutation succeeds

* fix scroll issue with model selector in dialog
This commit is contained in:
Cole Goldsmith 2025-11-07 11:49:57 -06:00 committed by GitHub
parent 2aecfc570c
commit 7e343ed1f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 37 additions and 11 deletions

View file

@ -7,6 +7,7 @@ import { useProviderHealthQuery } from "@/src/app/api/queries/useProviderHealthQ
import { Button } from "./ui/button";
import { useRouter } from "next/navigation";
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import { ModelProvider } from "@/app/settings/helpers/model-helpers";
interface ProviderHealthBannerProps {
className?: string;
@ -42,12 +43,22 @@ export function useProviderHealth() {
};
}
const providerTitleMap: Record<ModelProvider, string> = {
openai: "OpenAI",
ollama: "Ollama",
watsonx: "IBM watsonx.ai",
};
export function ProviderHealthBanner({ className }: ProviderHealthBannerProps) {
const { isLoading, isHealthy, isUnhealthy, health } = useProviderHealth();
const router = useRouter();
const { data: settings = {} } = useGetSettingsQuery();
const providerTitle =
providerTitleMap[settings.provider?.model_provider as ModelProvider] ||
"Provider";
// Only show banner when provider is unhealthy (not when backend is unavailable)
if (isLoading || isHealthy) {
return null;
@ -71,7 +82,7 @@ export function ProviderHealthBanner({ className }: ProviderHealthBannerProps) {
icon={AlertTriangle}
/>
<BannerTitle className="font-medium flex items-center gap-2">
{errorMessage}
{providerTitle} error - {errorMessage}
</BannerTitle>
<Button size="sm" onClick={() => router.push(settingsUrl)}>
Fix Setup

View file

@ -4,6 +4,7 @@ import {
useQueryClient,
} from "@tanstack/react-query";
import type { Settings } from "../queries/useGetSettingsQuery";
import { useGetCurrentProviderModelsQuery } from "../queries/useGetModelsQuery";
export interface UpdateSettingsRequest {
// Agent settings
@ -37,6 +38,7 @@ export const useUpdateSettingsMutation = (
>
) => {
const queryClient = useQueryClient();
const { refetch: refetchModels } = useGetCurrentProviderModelsQuery();
async function updateSettings(
variables: UpdateSettingsRequest
@ -63,6 +65,7 @@ export const useUpdateSettingsMutation = (
queryClient.invalidateQueries({
queryKey: ["settings"],
});
refetchModels(); // Refetch models for the settings page
options?.onSuccess?.(...args);
},
onError: options?.onError,

View file

@ -1,9 +1,9 @@
import { ModelProvider } from "@/app/settings/helpers/model-helpers";
import {
type UseQueryOptions,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { useGetSettingsQuery } from "./useGetSettingsQuery";
export interface ProviderHealthDetails {
llm_model: string;
@ -22,12 +22,6 @@ export interface ProviderHealthParams {
provider?: "openai" | "ollama" | "watsonx";
}
const providerTitleMap: Record<ModelProvider, string> = {
openai: "OpenAI",
ollama: "Ollama",
watsonx: "IBM watsonx.ai",
};
export const useProviderHealthQuery = (
params?: ProviderHealthParams,
options?: Omit<
@ -37,6 +31,8 @@ export const useProviderHealthQuery = (
) => {
const queryClient = useQueryClient();
const { data: settings = {} } = useGetSettingsQuery();
async function checkProviderHealth(): Promise<ProviderHealthResponse> {
try {
const url = new URL("/api/provider/health", window.location.origin);
@ -84,6 +80,7 @@ export const useProviderHealthQuery = (
queryKey: ["provider", "health"],
queryFn: checkProviderHealth,
retry: false, // Don't retry health checks automatically
enabled: !!settings?.edited && options?.enabled !== false, // Only run after onboarding is complete
...options,
},
queryClient

View file

@ -57,7 +57,7 @@ export function ModelSelector({
}, [options, value, custom, onValueChange]);
return (
<Popover open={open} onOpenChange={setOpen}>
<Popover open={open} onOpenChange={setOpen} modal={false}>
<PopoverTrigger asChild>
{/** biome-ignore lint/a11y/useSemanticElements: has to be a Button */}
<Button
@ -99,7 +99,8 @@ export function ModelSelector({
</PopoverTrigger>
<PopoverContent
align="start"
className=" p-0 w-[var(--radix-popover-trigger-width)]"
className="p-0 w-[var(--radix-popover-trigger-width)]"
onOpenAutoFocus={(e) => e.preventDefault()}
>
<Command>
<CommandInput
@ -107,7 +108,10 @@ export function ModelSelector({
value={searchValue}
onValueChange={setSearchValue}
/>
<CommandList>
<CommandList
className="max-h-[300px] overflow-y-auto"
onWheel={(e) => e.stopPropagation()}
>
<CommandEmpty>{noOptionsPlaceholder}</CommandEmpty>
<CommandGroup>
{options.map((option) => (

View file

@ -26,6 +26,8 @@ import { IBMOnboarding } from "./ibm-onboarding";
import { OllamaOnboarding } from "./ollama-onboarding";
import { OpenAIOnboarding } from "./openai-onboarding";
import { TabTrigger } from "./tab-trigger";
import { ProviderHealthResponse } from "@/app/api/queries/useProviderHealthQuery";
import { useQueryClient } from "@tanstack/react-query";
interface OnboardingCardProps {
onComplete: () => void;
@ -57,6 +59,8 @@ const OnboardingCard = ({
const [loadingStep, setLoadingStep] = useState<number>(0);
const queryClient = useQueryClient();
// Reset loading step when models start loading
useEffect(() => {
if (isLoadingModels) {
@ -129,6 +133,13 @@ const OnboardingCard = ({
const onboardingMutation = useOnboardingMutation({
onSuccess: (data) => {
console.log("Onboarding completed successfully", data);
// Update provider health cache to healthy since backend just validated
const healthData: ProviderHealthResponse = {
status: "healthy",
message: "Provider is configured and working correctly",
provider: settings.model_provider,
};
queryClient.setQueryData(["provider", "health"], healthData);
setCurrentStep(0);
setError(null);
},