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.
This commit is contained in:
@@ -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 @@
|
|||||||
></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 @@
|
|||||||
<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'
|
|||||||
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('')
|
|||||||
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)
|
|||||||
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 = [
|
|||||||
{ 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 = [
|
|||||||
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 = [
|
|||||||
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) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 => {
|
||||||
|
|||||||
Reference in New Issue
Block a user