Model Switcher UI improvements: highlight color, notification removal, preset display & validation
keyboardstaff committed
Mar 16, 2026 at 23:38 UTC
5acdd4d3025841d8df6c6d9dadd6472c491a3a47
3 files changed
+54
-15
plugins/_model_config/extensions/webui/chat-input-start/model-switcher.html
+49
-11
@@ -28,7 +28,6 @@
28
<template x-if="$store.modelConfig.switcherOverride">
29
<div class="model-switcher-item revert" @click="
30
$store.modelConfig.clearOverrideSwitch($store.chats?.selected || '');
31
- justToast('Reverted to default model', 'info');
31
showDropdown = false;
32
">
33
<span class="material-symbols-outlined" style="font-size: 15px;">undo</span>
@@ -48,12 +47,31 @@
47
:class="{ 'active': $store.modelConfig.switcherOverride?.preset_name === preset.name }"
48
@click="
49
$store.modelConfig.selectPresetSwitch($store.chats?.selected || '', preset.name);
51
- justToast('Switched to ' + preset.name, 'success');
50
showDropdown = false;
51
">
52
<div class="model-switcher-preset-name" x-text="preset.name"></div>
55
- <div class="model-switcher-preset-detail"
56
- x-text="$store.modelConfig.getPresetSummary(preset)"></div>
53
+ <div class="model-switcher-preset-models">
54
+ <template x-if="preset.chat?.name">
55
+ <div class="model-switcher-model-row">
56
+ <span class="model-switcher-model-label">Main</span>
57
+ <span class="model-switcher-model-value">
58
+ <span x-text="preset.chat.provider" style="opacity:0.5;"></span>
59
+ <span style="opacity:0.3; margin:0 3px;">/</span>
60
+ <span x-text="preset.chat.name"></span>
61
+ </span>
62
+ </div>
63
+ </template>
64
+ <template x-if="preset.utility?.name">
65
+ <div class="model-switcher-model-row">
66
+ <span class="model-switcher-model-label">Utility</span>
67
+ <span class="model-switcher-model-value">
68
+ <span x-text="preset.utility.provider" style="opacity:0.5;"></span>
69
+ <span style="opacity:0.3; margin:0 3px;">/</span>
70
+ <span x-text="preset.utility.name"></span>
71
+ </span>
72
+ </div>
73
+ </template>
74
+ </div>
75
</div>
76
</template>
77
</div>
@@ -95,8 +113,8 @@
113
color: var(--color-text-secondary, #666);
114
}
115
.model-switcher-btn.has-override {
98
- border-color: var(--color-accent, #4a9eff);
99
- color: var(--color-accent, #4a9eff);
116
+ border-color: var(--color-highlight);
117
+ color: var(--color-highlight);
118
}
119
.model-switcher-label {
120
max-width: 160px;
@@ -128,8 +146,7 @@
146
background: var(--color-background-hover, rgba(255,255,255,0.06));
147
}
148
.model-switcher-item.active {
131
- background: var(--color-accent-bg, rgba(74, 158, 255, 0.12));
132
- color: var(--color-accent, #4a9eff);
149
+ background: color-mix(in srgb, var(--color-highlight) 12%, transparent);
150
}
151
.model-switcher-item.revert {
152
display: flex;
@@ -153,9 +170,30 @@
170
.model-switcher-preset-name {
171
font-weight: 500;
172
}
156
- .model-switcher-preset-detail {
173
+ .model-switcher-preset-models {
174
+ display: flex;
175
+ flex-direction: column;
176
+ gap: 2px;
177
+ margin-top: 4px;
178
+ }
179
+ .model-switcher-model-row {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 6px;
183
font-size: 0.7rem;
158
- opacity: 0.6;
159
- margin-top: 1px;
184
+ opacity: 0.7;
185
+ }
186
+ .model-switcher-model-label {
187
+ width: 40px;
188
+ flex-shrink: 0;
189
+ font-weight: 500;
190
+ opacity: 0.7;
191
+ }
192
+ .model-switcher-model-value {
193
+ flex: 1;
194
+ min-width: 0;
195
+ overflow: hidden;
196
+ text-overflow: ellipsis;
197
+ white-space: nowrap;
198
}
199
</style>
plugins/_model_config/webui/config.html
+4
-3
@@ -50,7 +50,7 @@
50
<span class="preset-card-summary" x-show="!expanded"
51
x-text="(preset.chat?.provider ? preset.chat.provider + '/' : '') + (preset.chat?.name || '')"></span>
52
<button class="text-button preset-delete-btn"
53
- @click.stop="config.model_presets = config.model_presets.filter((_, i) => i !== idx)"
53
+ @click.stop="$confirmClick($event, () => { config.model_presets = config.model_presets.filter((_, i) => i !== idx) })"
54
title="Remove preset">
55
<span class="material-symbols-outlined" style="font-size:16px;">close</span>
56
</button>
@@ -62,7 +62,8 @@
62
<div class="field-title">Preset name</div>
63
<div class="field-description">Display name shown in the model switcher dropdown.</div>
64
</div>
65
- <div class="field-control"><input type="text" x-model="preset.name" placeholder="e.g. GPT-4o, Claude Sonnet" /></div>
65
+ <div class="field-control"><input type="text" x-model="preset.name" placeholder="e.g. GPT-4o, Claude Sonnet"
66
+ @blur="if (!preset.name.trim()) preset.name = 'Preset ' + (idx + 1)" required /></div>
67
</div>
68
69
<div class="preset-subheader">Main Model</div>
@@ -221,7 +222,7 @@
222
@click="
223
if (!config.model_presets) config.model_presets = [];
224
config.model_presets = [...config.model_presets, {
224
- name: '',
225
+ name: 'Preset ' + (config.model_presets.length + 1),
226
chat: { provider: config.chat_model.provider || '', name: config.chat_model.name || '', api_key: '', api_base: config.chat_model.api_base || '' },
227
utility: { provider: '', name: '', api_key: '', api_base: '' }
228
}]">
plugins/_model_config/webui/model-config-store.js
+1
-1
@@ -175,7 +175,7 @@ export const store = createStore("modelConfig", {
175
const cfgData = await this._fetchConfigData();
176
const chatCfg = cfgData.config?.chat_model || {};
177
result.allowed = !!chatCfg.allow_chat_override;
178
- result.presets = cfgData.config?.model_presets || [];
178
+ result.presets = (cfgData.config?.model_presets || []).filter(p => p.name);
179
if (!result.allowed) return result;
180
if (contextId) {
181
const overRes = await fetchApi(`${API_BASE}/model_override`, {