This commit is contained in:
9qeklajc
2025-11-04 23:46:38 +01:00
parent 88fbefbd18
commit f5c9cde852
9 changed files with 85 additions and 61 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ export default function RootLayout({
return (
<html lang='en' suppressHydrationWarning>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased font-sans`}
className={`${geistSans.variable} ${geistMono.variable} font-sans antialiased`}
>
<SuppressHydrationWarning>
<Providers>{children}</Providers>
+5 -1
View File
@@ -156,7 +156,10 @@ export default function ModelsPage() {
models={models}
onFilteredModelsChange={setFilteredModels}
/>
<ModelSelector filteredModels={filteredModels} />
<ModelSelector
filteredModels={filteredModels}
showDeleteAllButton={true}
/>
</div>
</TabsContent>
@@ -199,6 +202,7 @@ export default function ModelsPage() {
filterProvider={provider}
groupData={groupData}
showProviderActions={true}
showDeleteAllButton={false}
/>
</div>
</TabsContent>
+58 -38
View File
@@ -277,7 +277,11 @@ export default function ProvidersPage() {
}
placeholder='https://api.example.com/v1'
disabled={hasFixedBaseUrl(formData.provider_type)}
className={hasFixedBaseUrl(formData.provider_type) ? 'cursor-not-allowed opacity-60' : ''}
className={
hasFixedBaseUrl(formData.provider_type)
? 'cursor-not-allowed opacity-60'
: ''
}
/>
</div>
<div className='grid gap-2'>
@@ -453,7 +457,8 @@ export default function ProvidersPage() {
<div className='space-y-2'>
{providerModels.db_models.length === 0 ? (
<div className='text-muted-foreground py-4 text-center text-sm'>
No models configured. Add custom models to use this provider.
No models configured. Add custom models to
use this provider.
</div>
) : (
<div className='space-y-2'>
@@ -495,7 +500,10 @@ export default function ProvidersPage() {
</div>
) : (
// Has provided models - show tabs
<Tabs defaultValue='provided' className='w-full'>
<Tabs
defaultValue='provided'
className='w-full'
>
<TabsList className='grid w-full grid-cols-2'>
<TabsTrigger
value='provided'
@@ -504,7 +512,9 @@ export default function ProvidersPage() {
<span className='hidden sm:inline'>
Provided Models
</span>
<span className='sm:hidden'>Provided</span>
<span className='sm:hidden'>
Provided
</span>
<Badge
variant='secondary'
className='ml-1 text-xs sm:ml-2'
@@ -534,7 +544,8 @@ export default function ProvidersPage() {
>
{providerModels.db_models.length > 0 && (
<div className='text-muted-foreground mb-3 text-sm'>
Custom models override or extend the provider&apos;s catalog.
Custom models override or extend the
provider&apos;s catalog.
</div>
)}
{providerModels.db_models.length === 0 ? (
@@ -543,39 +554,42 @@ export default function ProvidersPage() {
</div>
) : (
<div className='space-y-2'>
{providerModels.db_models.map((model) => (
<div
key={model.id}
className='hover:bg-accent flex flex-col gap-2 rounded-lg border p-3 transition-colors sm:flex-row sm:items-center sm:justify-between'
>
<div className='min-w-0 flex-1'>
<div className='flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2'>
<span className='truncate font-mono text-sm font-medium'>
{model.id}
</span>
<Badge
variant={
model.enabled
? 'default'
: 'secondary'
}
className='w-fit text-xs'
>
{model.enabled
? 'Enabled'
: 'Disabled'}
</Badge>
{providerModels.db_models.map(
(model) => (
<div
key={model.id}
className='hover:bg-accent flex flex-col gap-2 rounded-lg border p-3 transition-colors sm:flex-row sm:items-center sm:justify-between'
>
<div className='min-w-0 flex-1'>
<div className='flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2'>
<span className='truncate font-mono text-sm font-medium'>
{model.id}
</span>
<Badge
variant={
model.enabled
? 'default'
: 'secondary'
}
className='w-fit text-xs'
>
{model.enabled
? 'Enabled'
: 'Disabled'}
</Badge>
</div>
<div className='text-muted-foreground mt-1 text-xs break-words'>
{model.description ||
model.name}
</div>
</div>
<div className='text-muted-foreground mt-1 text-xs break-words'>
{model.description || model.name}
<div className='text-muted-foreground text-xs whitespace-nowrap'>
{model.context_length?.toLocaleString()}{' '}
tokens
</div>
</div>
<div className='text-muted-foreground text-xs whitespace-nowrap'>
{model.context_length?.toLocaleString()}{' '}
tokens
</div>
</div>
))}
)
)}
</div>
)}
</TabsContent>
@@ -583,9 +597,11 @@ export default function ProvidersPage() {
value='provided'
className='mt-4 space-y-2'
>
{providerModels.remote_models.length > 0 && (
{providerModels.remote_models.length >
0 && (
<div className='text-muted-foreground mb-3 text-sm'>
Models automatically discovered from the provider&apos;s catalog.
Models automatically discovered from the
provider&apos;s catalog.
</div>
)}
<div className='space-y-2'>
@@ -670,7 +686,11 @@ export default function ProvidersPage() {
}
placeholder='https://api.example.com/v1'
disabled={hasFixedBaseUrl(formData.provider_type)}
className={hasFixedBaseUrl(formData.provider_type) ? 'cursor-not-allowed opacity-60' : ''}
className={
hasFixedBaseUrl(formData.provider_type)
? 'cursor-not-allowed opacity-60'
: ''
}
/>
</div>
<div className='grid gap-2'>
+11 -7
View File
@@ -65,12 +65,14 @@ interface ModelSelectorProps {
groupData?: ModelGroup;
showProviderActions?: boolean;
filteredModels?: Model[];
showDeleteAllButton?: boolean;
}
export function ModelSelector({
filterProvider,
groupData,
filteredModels: propFilteredModels,
showDeleteAllButton = false,
}: ModelSelectorProps) {
const [selectedModelId, setSelectedModelId] = useState<string>('');
const [, setHoveredModelId] = useState<string | null>(null);
@@ -824,13 +826,15 @@ export function ModelSelector({
<Square className='mr-2 h-4 w-4' />
Deselect All
</Button>
<Button
onClick={handleDeleteAll}
className='text-destructive focus:text-destructive'
>
<AlertTriangle className='mr-2 h-4 w-4' />
Delete All Models Permanently
</Button>
{showDeleteAllButton && (
<Button
onClick={handleDeleteAll}
className='text-destructive focus:text-destructive'
>
<AlertTriangle className='mr-2 h-4 w-4' />
Delete All Overrides Permanently
</Button>
)}
{/* Model Management Actions
<Button onClick={() => setIsAddFormOpen(true)} className='gap-2'>
<Plus className='h-4 w-4' />
+5 -3
View File
@@ -203,7 +203,8 @@ export function DetailedWalletBalance({
<div
className={cn(
'text-right font-mono',
!detail.error && ownerMsat > 0 &&
!detail.error &&
ownerMsat > 0 &&
'font-semibold text-green-600'
)}
>
@@ -250,7 +251,8 @@ export function DetailedWalletBalance({
<div
className={cn(
'truncate font-mono text-sm',
!detail.error && ownerMsat > 0 &&
!detail.error &&
ownerMsat > 0 &&
'font-semibold text-green-600'
)}
>
@@ -283,4 +285,4 @@ export function DetailedWalletBalance({
/>
</>
);
}
}
+5 -8
View File
@@ -11,10 +11,7 @@ import {
DollarSign,
Activity,
} from 'lucide-react';
import {
AdminService,
TemporaryBalance,
} from '@/lib/api/services/admin';
import { AdminService, TemporaryBalance } from '@/lib/api/services/admin';
import {
Card,
CardContent,
@@ -243,16 +240,16 @@ export function TemporaryBalances({
<div className='text-muted-foreground text-xs font-medium'>
Balance
</div>
<div className='truncate font-mono text-sm'>
{formatBalance(balance.balance)}
<div className='truncate font-mono text-sm'>
{formatBalance(balance.balance)}
</div>
</div>
<div className='space-y-1'>
<div className='text-muted-foreground text-xs font-medium'>
Spent
</div>
<div className='truncate font-mono text-sm'>
{formatBalance(balance.total_spent)}
<div className='truncate font-mono text-sm'>
{formatBalance(balance.total_spent)}
</div>
</div>
</div>
-1
View File
@@ -43,4 +43,3 @@ export function formatFromMsat(
});
return formatter.format(usd);
}
-1
View File
@@ -51,4 +51,3 @@ export async function fetchBtcUsdPrice(): Promise<number | null> {
export function btcToSatsRate(btcUsdPrice: number): number {
return btcUsdPrice / 100_000_000;
}
-1
View File
@@ -14,4 +14,3 @@ export function getDisplayUnitLabel(unit: DisplayUnit): string {
return unit;
}
}