Commit fb3ef5f3 authored by erio's avatar erio
Browse files

fix(frontend): add Gemini models to bulk edit and fix status grid layout

Add Gemini model presets to BulkEditAccountModal for bulk model mapping.
Fix AccountStatusIndicator model rate limit grid layout using proper
grid container.
parent 86bc76e3
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
</div> </div>
<!-- Model Rate Limit Indicators (Antigravity OAuth Smart Retry) --> <!-- Model Rate Limit Indicators (Antigravity OAuth Smart Retry) -->
<template v-if="activeModelRateLimits.length > 0"> <div v-if="activeModelRateLimits.length > 0" class="grid grid-cols-3 gap-1">
<div v-for="item in activeModelRateLimits" :key="item.model" class="group relative"> <div v-for="item in activeModelRateLimits" :key="item.model" class="group relative">
<span <span
class="inline-flex items-center gap-1 rounded bg-purple-100 px-1.5 py-0.5 text-xs font-medium text-purple-700 dark:bg-purple-900/30 dark:text-purple-400" class="inline-flex items-center gap-1 rounded bg-purple-100 px-1.5 py-0.5 text-xs font-medium text-purple-700 dark:bg-purple-900/30 dark:text-purple-400"
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
></div> ></div>
</div> </div>
</div> </div>
</template> </div>
<!-- Overload Indicator (529) --> <!-- Overload Indicator (529) -->
<div v-if="isOverloaded" class="group relative"> <div v-if="isOverloaded" class="group relative">
......
...@@ -209,7 +209,7 @@ ...@@ -209,7 +209,7 @@
<div v-if="modelMappings.length > 0" class="mb-3 space-y-2"> <div v-if="modelMappings.length > 0" class="mb-3 space-y-2">
<div <div
v-for="(mapping, index) in modelMappings" v-for="(mapping, index) in modelMappings"
:key="getModelMappingKey(mapping)" :key="index"
class="flex items-center gap-2" class="flex items-center gap-2"
> >
<input <input
...@@ -654,7 +654,7 @@ import Select from '@/components/common/Select.vue' ...@@ -654,7 +654,7 @@ import Select from '@/components/common/Select.vue'
import ProxySelector from '@/components/common/ProxySelector.vue' import ProxySelector from '@/components/common/ProxySelector.vue'
import GroupSelector from '@/components/common/GroupSelector.vue' import GroupSelector from '@/components/common/GroupSelector.vue'
import Icon from '@/components/icons/Icon.vue' import Icon from '@/components/icons/Icon.vue'
import { createStableObjectKeyResolver } from '@/utils/stableObjectKey' import { buildModelMappingObject as buildModelMappingPayload } from '@/composables/useModelWhitelist'
interface Props { interface Props {
show: boolean show: boolean
...@@ -696,7 +696,6 @@ const baseUrl = ref('') ...@@ -696,7 +696,6 @@ const baseUrl = ref('')
const modelRestrictionMode = ref<'whitelist' | 'mapping'>('whitelist') const modelRestrictionMode = ref<'whitelist' | 'mapping'>('whitelist')
const allowedModels = ref<string[]>([]) const allowedModels = ref<string[]>([])
const modelMappings = ref<ModelMapping[]>([]) const modelMappings = ref<ModelMapping[]>([])
const getModelMappingKey = createStableObjectKeyResolver<ModelMapping>('bulk-model-mapping')
const selectedErrorCodes = ref<number[]>([]) const selectedErrorCodes = ref<number[]>([])
const customErrorCodeInput = ref<number | null>(null) const customErrorCodeInput = ref<number | null>(null)
const interceptWarmupRequests = ref(false) const interceptWarmupRequests = ref(false)
...@@ -707,7 +706,7 @@ const rateMultiplier = ref(1) ...@@ -707,7 +706,7 @@ const rateMultiplier = ref(1)
const status = ref<'active' | 'inactive'>('active') const status = ref<'active' | 'inactive'>('active')
const groupIds = ref<number[]>([]) const groupIds = ref<number[]>([])
// All models list (combined Anthropic + OpenAI) // All models list (combined Anthropic + OpenAI + Gemini)
const allModels = [ const allModels = [
{ value: 'claude-opus-4-6', label: 'Claude Opus 4.6' }, { value: 'claude-opus-4-6', label: 'Claude Opus 4.6' },
{ value: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6' }, { value: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6' },
...@@ -719,17 +718,21 @@ const allModels = [ ...@@ -719,17 +718,21 @@ const allModels = [
{ value: 'claude-3-opus-20240229', label: 'Claude 3 Opus' }, { value: 'claude-3-opus-20240229', label: 'Claude 3 Opus' },
{ value: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet' }, { value: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet' },
{ value: 'claude-3-haiku-20240307', label: 'Claude 3 Haiku' }, { value: 'claude-3-haiku-20240307', label: 'Claude 3 Haiku' },
{ value: 'gpt-5.3-codex-spark', label: 'GPT-5.3 Codex Spark' },
{ value: 'gpt-5.2-2025-12-11', label: 'GPT-5.2' }, { value: 'gpt-5.2-2025-12-11', label: 'GPT-5.2' },
{ value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex' }, { value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex' },
{ value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' }, { value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' },
{ value: 'gpt-5.1-codex', label: 'GPT-5.1 Codex' }, { value: 'gpt-5.1-codex', label: 'GPT-5.1 Codex' },
{ value: 'gpt-5.1-2025-11-13', label: 'GPT-5.1' }, { value: 'gpt-5.1-2025-11-13', label: 'GPT-5.1' },
{ value: 'gpt-5.1-codex-mini', label: 'GPT-5.1 Codex Mini' }, { value: 'gpt-5.1-codex-mini', label: 'GPT-5.1 Codex Mini' },
{ value: 'gpt-5-2025-08-07', label: 'GPT-5' } { value: 'gpt-5-2025-08-07', label: 'GPT-5' },
{ value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash' },
{ value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' },
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' },
{ value: 'gemini-3-flash-preview', label: 'Gemini 3 Flash Preview' },
{ value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro Preview' }
] ]
// Preset mappings (combined Anthropic + OpenAI) // Preset mappings (combined Anthropic + OpenAI + Gemini)
const presetMappings = [ const presetMappings = [
{ {
label: 'Sonnet 4', label: 'Sonnet 4',
...@@ -771,12 +774,6 @@ const presetMappings = [ ...@@ -771,12 +774,6 @@ const presetMappings = [
to: 'claude-sonnet-4-5-20250929', to: 'claude-sonnet-4-5-20250929',
color: 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400' color: 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400'
}, },
{
label: 'GPT-5.3 Codex Spark',
from: 'gpt-5.3-codex-spark',
to: 'gpt-5.3-codex-spark',
color: 'bg-teal-100 text-teal-700 hover:bg-teal-200 dark:bg-teal-900/30 dark:text-teal-400'
},
{ {
label: 'GPT-5.2', label: 'GPT-5.2',
from: 'gpt-5.2-2025-12-11', from: 'gpt-5.2-2025-12-11',
...@@ -794,6 +791,24 @@ const presetMappings = [ ...@@ -794,6 +791,24 @@ const presetMappings = [
from: 'gpt-5.1-codex-max', from: 'gpt-5.1-codex-max',
to: 'gpt-5.1-codex', to: 'gpt-5.1-codex',
color: 'bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400' color: 'bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400'
},
{
label: 'Gemini Flash 2.0',
from: 'gemini-2.0-flash',
to: 'gemini-2.0-flash',
color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400'
},
{
label: 'Gemini 2.5 Flash',
from: 'gemini-2.5-flash',
to: 'gemini-2.5-flash',
color: 'bg-teal-100 text-teal-700 hover:bg-teal-200 dark:bg-teal-900/30 dark:text-teal-400'
},
{
label: 'Gemini 2.5 Pro',
from: 'gemini-2.5-pro',
to: 'gemini-2.5-pro',
color: 'bg-sky-100 text-sky-700 hover:bg-sky-200 dark:bg-sky-900/30 dark:text-sky-400'
} }
] ]
...@@ -883,23 +898,11 @@ const removeErrorCode = (code: number) => { ...@@ -883,23 +898,11 @@ const removeErrorCode = (code: number) => {
} }
const buildModelMappingObject = (): Record<string, string> | null => { const buildModelMappingObject = (): Record<string, string> | null => {
const mapping: Record<string, string> = {} return buildModelMappingPayload(
modelRestrictionMode.value,
if (modelRestrictionMode.value === 'whitelist') { allowedModels.value,
for (const model of allowedModels.value) { modelMappings.value
mapping[model] = model )
}
} else {
for (const m of modelMappings.value) {
const from = m.from.trim()
const to = m.to.trim()
if (from && to) {
mapping[from] = to
}
}
}
return Object.keys(mapping).length > 0 ? mapping : null
} }
const buildUpdatePayload = (): Record<string, unknown> | null => { const buildUpdatePayload = (): Record<string, unknown> | null => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment