fix(app): use shared provider snapshot hook in settings and add refresh button

Settings providers section now uses useProvidersSnapshot instead of a
one-shot fetch, so it shares the same real-time data source as the
status bar and draft form. Adds a Refresh button to re-detect installed
provider CLIs without restarting the daemon.
This commit is contained in:
Mohamed Boudra
2026-04-07 14:17:52 +07:00
parent bdaa6b65aa
commit 52dfdb1913
+26 -32
View File
@@ -62,12 +62,12 @@ import { settingsStyles } from "@/styles/settings";
import { THINKING_TONE_NATIVE_PCM_BASE64 } from "@/utils/thinking-tone.native-pcm"; import { THINKING_TONE_NATIVE_PCM_BASE64 } from "@/utils/thinking-tone.native-pcm";
import { useVoiceAudioEngineOptional } from "@/contexts/voice-context"; import { useVoiceAudioEngineOptional } from "@/contexts/voice-context";
import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon"; import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot";
import { isCompactFormFactor } from "@/constants/layout"; import { isCompactFormFactor } from "@/constants/layout";
import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest"; import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest";
import { getProviderIcon } from "@/components/provider-icons"; import { getProviderIcon } from "@/components/provider-icons";
import { ProviderDiagnosticSheet } from "@/components/provider-diagnostic-sheet"; import { ProviderDiagnosticSheet } from "@/components/provider-diagnostic-sheet";
import { StatusBadge } from "@/components/ui/status-badge"; import { StatusBadge } from "@/components/ui/status-badge";
import type { ProviderSnapshotEntry } from "@server/server/agent/agent-sdk-types";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Section definitions // Section definitions
@@ -432,55 +432,49 @@ interface ProvidersSectionProps {
function ProvidersSection({ routeServerId }: ProvidersSectionProps) { function ProvidersSection({ routeServerId }: ProvidersSectionProps) {
const { theme } = useUnistyles(); const { theme } = useUnistyles();
const client = useHostRuntimeClient(routeServerId);
const isConnected = useHostRuntimeIsConnected(routeServerId); const isConnected = useHostRuntimeIsConnected(routeServerId);
const [entries, setEntries] = useState<ProviderSnapshotEntry[]>([]); const { entries, isLoading, isFetching, refresh } = useProvidersSnapshot(routeServerId);
const [loading, setLoading] = useState(false);
const [diagnosticProvider, setDiagnosticProvider] = useState<string | null>(null); const [diagnosticProvider, setDiagnosticProvider] = useState<string | null>(null);
useEffect(() => {
if (!client || !isConnected) {
setEntries([]);
return;
}
let cancelled = false;
setLoading(true);
client
.getProvidersSnapshot()
.then((result) => {
if (!cancelled) setEntries(result.entries);
})
.catch(() => {
if (!cancelled) setEntries([]);
})
.finally(() => {
if (!cancelled) setLoading(false);
});
return () => {
cancelled = true;
};
}, [client, isConnected]);
const hasServer = routeServerId.length > 0; const hasServer = routeServerId.length > 0;
return ( return (
<> <>
<View style={settingsStyles.section}> <View style={settingsStyles.section}>
<Text style={settingsStyles.sectionTitle}>Providers</Text> <View style={settingsStyles.sectionHeader}>
<Text style={settingsStyles.sectionHeaderTitle}>Providers</Text>
{hasServer && isConnected ? (
<Pressable
onPress={refresh}
disabled={isFetching}
style={[
settingsStyles.sectionHeaderLink,
isFetching ? { opacity: 0.5 } : null,
]}
>
<Text
style={{
color: theme.colors.primary,
fontSize: theme.fontSize.xs,
}}
>
Refresh
</Text>
</Pressable>
) : null}
</View>
{!hasServer || !isConnected ? ( {!hasServer || !isConnected ? (
<View style={[settingsStyles.card, styles.emptyCard]}> <View style={[settingsStyles.card, styles.emptyCard]}>
<Text style={styles.emptyText}>Connect to a host to see providers</Text> <Text style={styles.emptyText}>Connect to a host to see providers</Text>
</View> </View>
) : loading ? ( ) : isLoading ? (
<View style={[settingsStyles.card, styles.emptyCard]}> <View style={[settingsStyles.card, styles.emptyCard]}>
<Text style={styles.emptyText}>Loading...</Text> <Text style={styles.emptyText}>Loading...</Text>
</View> </View>
) : ( ) : (
<View style={[settingsStyles.card, styles.audioCard]}> <View style={[settingsStyles.card, styles.audioCard]}>
{AGENT_PROVIDER_DEFINITIONS.map((def) => { {AGENT_PROVIDER_DEFINITIONS.map((def) => {
const entry = entries.find((e) => e.provider === def.id); const entry = entries?.find((e) => e.provider === def.id);
const status = entry?.status ?? "unavailable"; const status = entry?.status ?? "unavailable";
const ProviderIcon = getProviderIcon(def.id); const ProviderIcon = getProviderIcon(def.id);