Vendor ACP provider catalog
This commit is contained in:
@@ -95,6 +95,7 @@ vi.mock("lucide-react-native", () => {
|
||||
const icon = (name: string) => () => React.createElement("span", { "data-icon": name });
|
||||
return {
|
||||
ChevronRight: icon("ChevronRight"),
|
||||
Plus: icon("Plus"),
|
||||
RotateCw: icon("RotateCw"),
|
||||
};
|
||||
});
|
||||
@@ -144,6 +145,10 @@ vi.mock("@/components/provider-diagnostic-sheet", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/add-provider-modal", () => ({
|
||||
AddProviderModal: () => null,
|
||||
}));
|
||||
|
||||
vi.mock("@/hooks/use-providers-snapshot", () => ({
|
||||
useProvidersSnapshot: () => ({
|
||||
entries: snapshotState.entries,
|
||||
@@ -323,7 +328,7 @@ describe("ProvidersSection", () => {
|
||||
expect(sheet?.getAttribute("data-provider")).toBe("codex");
|
||||
});
|
||||
|
||||
it("toggles the provider enabled flag through patchConfig when the switch is pressed", () => {
|
||||
it("toggles the provider enabled flag through patchConfig when the switch is pressed", async () => {
|
||||
snapshotState.entries = [claudeEntry];
|
||||
configState.config = makeConfig();
|
||||
|
||||
@@ -334,7 +339,7 @@ describe("ProvidersSection", () => {
|
||||
expect(switchEl).not.toBeNull();
|
||||
expect(switchEl?.getAttribute("aria-checked")).toBe("true");
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
switchEl?.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user