Vendor ACP provider catalog

This commit is contained in:
Mohamed Boudra
2026-05-06 20:00:40 +08:00
committed by GitHub
parent ac375f152d
commit c36f4cfee4
46 changed files with 1605 additions and 28 deletions
@@ -6,12 +6,13 @@ import { useHostRuntimeIsConnected } from "@/runtime/host-runtime";
import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot";
import { useDaemonConfig } from "@/hooks/use-daemon-config";
import { buildProviderDefinitions } from "@/utils/provider-definitions";
import { AddProviderModal } from "@/components/add-provider-modal";
import { getProviderIcon } from "@/components/provider-icons";
import { ProviderDiagnosticSheet } from "@/components/provider-diagnostic-sheet";
import { LoadingSpinner } from "@/components/ui/loading-spinner";
import { Switch } from "@/components/ui/switch";
import { SettingsSection } from "@/screens/settings/settings-section";
import { ChevronRight, RotateCw } from "lucide-react-native";
import { ChevronRight, Plus, RotateCw } from "lucide-react-native";
type ProviderDefinition = ReturnType<typeof buildProviderDefinitions>[number];
type ProviderEntry = NonNullable<ReturnType<typeof useProvidersSnapshot>["entries"]>[number];
@@ -181,6 +182,7 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
const { entries, isLoading, isRefreshing, refresh } = useProvidersSnapshot(serverId);
const { patchConfig } = useDaemonConfig(serverId);
const [diagnosticProvider, setDiagnosticProvider] = useState<string | null>(null);
const [isAddProviderOpen, setIsAddProviderOpen] = useState(false);
const [pendingProviderId, setPendingProviderId] = useState<string | null>(null);
const providerDefinitions = useMemo(() => buildProviderDefinitions(entries), [entries]);
@@ -193,6 +195,8 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
}, [refresh]);
const handleCloseDiagnostic = useCallback(() => setDiagnosticProvider(null), []);
const handleOpenAddProvider = useCallback(() => setIsAddProviderOpen(true), []);
const handleCloseAddProvider = useCallback(() => setIsAddProviderOpen(false), []);
const handleToggleEnabled = useCallback(
async (providerId: string, enabled: boolean) => {
setPendingProviderId(providerId);
@@ -210,29 +214,43 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
[patchConfig],
);
const refreshAction = useMemo(
const headerActions = useMemo(
() =>
hasServer && isConnected ? (
<Pressable
onPress={handleRefresh}
disabled={providerRefreshInFlight}
hitSlop={8}
style={settingsStyles.sectionHeaderLink}
accessibilityRole="button"
accessibilityLabel={
providerRefreshInFlight ? "Refreshing providers" : "Refresh providers"
}
>
{providerRefreshInFlight ? (
<LoadingSpinner size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
) : (
<RotateCw size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
)}
</Pressable>
<View style={styles.headerActions}>
<Pressable
onPress={handleOpenAddProvider}
hitSlop={8}
style={settingsStyles.sectionHeaderLink}
accessibilityRole="button"
accessibilityLabel="Add provider"
testID="add-provider-button"
>
<Plus size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
<Text style={settingsStyles.sectionHeaderLinkText}>Add provider</Text>
</Pressable>
<Pressable
onPress={handleRefresh}
disabled={providerRefreshInFlight}
hitSlop={8}
style={settingsStyles.sectionHeaderLink}
accessibilityRole="button"
accessibilityLabel={
providerRefreshInFlight ? "Refreshing providers" : "Refresh providers"
}
>
{providerRefreshInFlight ? (
<LoadingSpinner size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
) : (
<RotateCw size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
)}
</Pressable>
</View>
) : undefined,
[
hasServer,
isConnected,
handleOpenAddProvider,
handleRefresh,
providerRefreshInFlight,
theme.iconSize.sm,
@@ -244,7 +262,7 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
<>
<SettingsSection
title="Providers"
trailing={refreshAction}
trailing={headerActions}
testID="host-page-providers-card"
style={styles.sectionSpacing}
>
@@ -288,6 +306,9 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
serverId={serverId}
/>
) : null}
{hasServer && isConnected && isAddProviderOpen ? (
<AddProviderModal serverId={serverId} visible onClose={handleCloseAddProvider} />
) : null}
</>
);
}
@@ -304,6 +325,11 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
headerActions: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[3],
},
row: {
gap: theme.spacing[3],
minHeight: 56,