diff --git a/ui/src/components/cliproxy-table.tsx b/ui/src/components/cliproxy-table.tsx
index af467c4b..b9f7e2bb 100644
--- a/ui/src/components/cliproxy-table.tsx
+++ b/ui/src/components/cliproxy-table.tsx
@@ -44,6 +44,7 @@ export function CliproxyTable({ data }: CliproxyTableProps) {
{
accessorKey: 'name',
header: 'Name',
+ cell: ({ row }) => {row.original.name},
},
{
accessorKey: 'provider',
@@ -56,11 +57,11 @@ export function CliproxyTable({ data }: CliproxyTableProps) {
cell: ({ row }) => {
const account = row.original.account;
if (!account) {
- return default;
+ return default;
}
return (
-
+
{account}
);
@@ -69,27 +70,35 @@ export function CliproxyTable({ data }: CliproxyTableProps) {
{
accessorKey: 'settings',
header: 'Settings Path',
+ cell: ({ row }) => (
+
+ {row.original.settings || `config.cliproxy.${row.original.name}`}
+
+ ),
},
{
id: 'actions',
header: 'Actions',
cell: ({ row }) => (
-
-
-
-
-
- deleteMutation.mutate(row.original.name)}
- >
-
- Delete
-
-
-
+
+
+
+
+
+
+ deleteMutation.mutate(row.original.name)}
+ >
+
+ Delete
+
+
+
+
),
},
];
@@ -103,16 +112,19 @@ export function CliproxyTable({ data }: CliproxyTableProps) {
if (data.length === 0) {
return (
-
- No CLIProxy variants found. Create one to use OAuth-based providers.
+
+
No CLIProxy variants found.
+
+ Create one to use OAuth-based providers with specific account configurations.
+
);
}
return (
-
+
-
+
{table.getHeaderGroups().map((headerGroup) => (
{headerGroup.headers.map((header) => (
diff --git a/ui/src/components/ui/dropdown-menu.tsx b/ui/src/components/ui/dropdown-menu.tsx
index dbb5b694..8e2f660d 100644
--- a/ui/src/components/ui/dropdown-menu.tsx
+++ b/ui/src/components/ui/dropdown-menu.tsx
@@ -31,7 +31,7 @@ function DropdownMenuContent({
data-slot="dropdown-menu-content"
sideOffset={sideOffset}
className={cn(
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md bg-white dark:bg-zinc-950',
className
)}
{...props}
diff --git a/ui/src/pages/cliproxy.tsx b/ui/src/pages/cliproxy.tsx
index 56b6cbbc..6ef4c94b 100644
--- a/ui/src/pages/cliproxy.tsx
+++ b/ui/src/pages/cliproxy.tsx
@@ -7,12 +7,12 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
+import { Card, CardContent } from '@/components/ui/card';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
- DropdownMenuSeparator,
} from '@/components/ui/dropdown-menu';
import { Plus, Check, X, User, ChevronDown, Star, Trash2 } from 'lucide-react';
import { CliproxyTable } from '@/components/cliproxy-table';
@@ -40,10 +40,10 @@ function AccountBadge({
-
-
- {account.email || account.id}
+
+
+
+ {account.email || account.id}
+
{account.lastUsedAt && (
-
- Last used: {new Date(account.lastUsedAt).toLocaleDateString()}
-
+
Last used: {new Date(account.lastUsedAt).toLocaleDateString()}
)}
-
{!account.isDefault && (
@@ -69,7 +68,7 @@ function AccountBadge({
)}
@@ -81,7 +80,7 @@ function AccountBadge({
);
}
-function ProviderCard({
+function ProviderRow({
status,
setDefaultMutation,
removeMutation,
@@ -91,79 +90,85 @@ function ProviderCard({
removeMutation: ReturnType;
}) {
const accounts = status.accounts || [];
- const hasMultipleAccounts = accounts.length > 1;
return (
-
-
-
- {status.authenticated ? (
-
- ) : (
-
- )}
-
{status.displayName}
+
+
+
+ {status.authenticated ? : }
- {accounts.length > 0 && (
-
- {accounts.length} account{accounts.length !== 1 ? 's' : ''}
-
+
+
+ {status.displayName}
+ {accounts.length > 0 && (
+
+ {accounts.length}
+
+ )}
+
+
{status.provider}
+
+
+
+
+ {status.authenticated && accounts.length > 0 ? (
+ accounts.map((account) => (
+
+ setDefaultMutation.mutate({
+ provider: status.provider,
+ accountId: account.id,
+ })
+ }
+ onRemove={() =>
+ removeMutation.mutate({
+ provider: status.provider,
+ accountId: account.id,
+ })
+ }
+ isRemoving={removeMutation.isPending}
+ />
+ ))
+ ) : (
+
+ {status.authenticated
+ ? 'Authenticated (No specific accounts tracked)'
+ : 'Not authenticated'}
+
)}
- {status.authenticated ? (
-
- {accounts.length > 0 ? (
-
- {accounts.map((account) => (
-
- setDefaultMutation.mutate({
- provider: status.provider,
- accountId: account.id,
- })
- }
- onRemove={() =>
- removeMutation.mutate({
- provider: status.provider,
- accountId: account.id,
- })
- }
- isRemoving={removeMutation.isPending}
- />
- ))}
-
- ) : (
-
- Authenticated
- {status.lastAuth && (
- ({new Date(status.lastAuth).toLocaleDateString()})
- )}
-
- )}
- {hasMultipleAccounts && (
-
- Click account to manage. Star = default.
-
- )}
-
- Add account:
ccs {status.provider} --auth
+
+ {!status.authenticated && (
+
+ ccs {status.provider} --auth
-
- ) : (
-
- Not authenticated
-
- Run: ccs {status.provider} --auth
-
-
- )}
+ )}
+ {status.authenticated && (
+
+ )}
+
);
}
@@ -176,12 +181,12 @@ export function CliproxyPage() {
const removeMutation = useRemoveAccount();
return (
-
-
+
+
-
CLIProxy
+
CLIProxy
- Manage OAuth-based provider variants with multi-account support
+ Manage OAuth-based provider variants and multi-account configurations
{/* Built-in Profiles with Account Management */}
-
-
Built-in Profiles & Accounts
- {authLoading ? (
-
Loading auth status...
- ) : (
-
- {authData?.authStatus.map((status) => (
-
- ))}
-
- )}
+
+
+
Built-in Providers
+
+ Manage authentication status and accounts for built-in providers.
+
+
+
+
+
+ {authLoading ? (
+
+ Loading authentication status...
+
+ ) : (
+
+ {authData?.authStatus.map((status) => (
+
+ ))}
+
+ )}
+
+
{/* Custom Variants */}
-
-
Custom Variants
+
+
+
+
Custom Variants
+
+ Create custom aliases for providers with specific accounts.
+
+
+
+
{isLoading ? (
Loading variants...
) : (