Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/browser/assets/icons/ollama.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions src/browser/assets/icons/openrouter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/browser/components/ProviderIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import AnthropicIcon from "@/browser/assets/icons/anthropic.svg?react";
import OpenAIIcon from "@/browser/assets/icons/openai.svg?react";
import GoogleIcon from "@/browser/assets/icons/google.svg?react";
import XAIIcon from "@/browser/assets/icons/xai.svg?react";
import OpenRouterIcon from "@/browser/assets/icons/openrouter.svg?react";
import OllamaIcon from "@/browser/assets/icons/ollama.svg?react";
import DeepSeekIcon from "@/browser/assets/icons/deepseek.svg?react";
import AWSIcon from "@/browser/assets/icons/aws.svg?react";
import { GatewayIcon } from "@/browser/components/icons/GatewayIcon";
Expand All @@ -23,7 +25,9 @@ const PROVIDER_ICONS: Partial<Record<ProviderName, React.FC>> = {
google: GoogleIcon,
xai: XAIIcon,
deepseek: DeepSeekIcon,
openrouter: OpenRouterIcon,
bedrock: AWSIcon,
ollama: OllamaIcon,
"mux-gateway": GatewayIcon,
};

Expand Down
41 changes: 15 additions & 26 deletions src/browser/components/Settings/sections/ProvidersSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import { ChevronDown, ChevronRight, Check, X, Eye, EyeOff, ExternalLink } from "

import { createEditKeyHandler } from "@/browser/utils/ui/keybinds";
import { SUPPORTED_PROVIDERS } from "@/common/constants/providers";
import { KNOWN_MODELS } from "@/common/constants/knownModels";
import type { ProvidersConfigMap } from "@/common/orpc/types";
import type { ProviderName } from "@/common/constants/providers";
import { ProviderWithIcon } from "@/browser/components/ProviderIcon";
import { getStoredAuthToken } from "@/browser/components/AuthTokenModal";
import { useAPI } from "@/browser/contexts/API";
import { useSettings } from "@/browser/contexts/SettingsContext";
import { usePersistedState } from "@/browser/hooks/usePersistedState";
import { getStoredAuthToken } from "@/browser/components/AuthTokenModal";
import { useProvidersConfig } from "@/browser/hooks/useProvidersConfig";
import { isProviderSupported, useGateway } from "@/browser/hooks/useGatewayModels";
import { useGateway } from "@/browser/hooks/useGatewayModels";
import { getEligibleGatewayModels } from "@/browser/utils/gatewayModels";
import { Button } from "@/browser/components/ui/button";
import {
Select,
Expand Down Expand Up @@ -49,29 +50,6 @@ function getBackendBaseUrl(): string {
}
const GATEWAY_MODELS_KEY = "gateway-models";

const BUILT_IN_MODELS: string[] = Object.values(KNOWN_MODELS).map((model) => model.id);

function getEligibleGatewayModels(config: ProvidersConfigMap | null): string[] {
const customModels: string[] = [];

if (config) {
for (const [provider, providerConfig] of Object.entries(config)) {
if (provider === "mux-gateway") continue;
for (const modelId of providerConfig.models ?? []) {
customModels.push(`${provider}:${modelId}`);
}
}
}

const unique = new Set<string>();
for (const modelId of [...customModels, ...BUILT_IN_MODELS]) {
if (!isProviderSupported(modelId)) continue;
unique.add(modelId);
}

return Array.from(unique).sort((a, b) => a.localeCompare(b));
}

interface FieldConfig {
key: string;
label: string;
Expand Down Expand Up @@ -144,6 +122,8 @@ const PROVIDER_KEY_URLS: Partial<Record<ProviderName, string>> = {
};

export function ProvidersSection() {
const { providersExpandedProvider, setProvidersExpandedProvider } = useSettings();

const { api } = useAPI();
const { config, updateOptimistically } = useProvidersConfig();

Expand Down Expand Up @@ -437,6 +417,15 @@ export function ProvidersSection() {
: "Login to Mux Gateway";

const [expandedProvider, setExpandedProvider] = useState<string | null>(null);

useEffect(() => {
if (!providersExpandedProvider) {
return;
}

setExpandedProvider(providersExpandedProvider);
setProvidersExpandedProvider(null);
}, [providersExpandedProvider, setProvidersExpandedProvider]);
const [editingField, setEditingField] = useState<{
provider: string;
field: string;
Expand Down
31 changes: 11 additions & 20 deletions src/browser/components/SettingsButton.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
import { Settings } from "lucide-react";
import { useSettings } from "@/browser/contexts/SettingsContext";
import { Tooltip, TooltipTrigger, TooltipContent } from "./ui/tooltip";
import { formatKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds";
import { Button } from "@/browser/components/ui/button";

export function SettingsButton() {
const { open } = useSettings();

return (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => open()}
className="border-border-light text-muted-foreground hover:border-border-medium/80 hover:bg-toggle-bg/70 h-5 w-5 border"
aria-label="Open settings"
data-testid="settings-button"
data-tutorial="settings-button"
>
<Settings className="h-3.5 w-3.5" aria-hidden />
</Button>
</TooltipTrigger>
<TooltipContent align="end">
Settings ({formatKeybind(KEYBINDS.OPEN_SETTINGS)})
</TooltipContent>
</Tooltip>
<Button
variant="ghost"
size="icon"
onClick={() => open()}
className="border-border-light text-muted-foreground hover:border-border-medium/80 hover:bg-toggle-bg/70 h-5 w-5 border"
aria-label="Open settings"
data-testid="settings-button"
data-tutorial="settings-button"
>
<Settings className="h-3.5 w-3.5" aria-hidden />
</Button>
);
}
Loading