Closes #2679 Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
This commit is contained in:
1 parent
c70ec3ba19
commit
7d3013245a
10 files changed
+119
No files matched your search
@@ -3,6 +3,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **PR #2687** by @Michaelyklam (closes #2679) — Add a Settings → Preferences toggle backed by `hide_empty_state_suggestions` to hide the three default new-chat suggestion buttons. The empty-state copy stays visible, but the suggestion grid can now be removed from fresh chats to avoid accidental mobile taps.
|
||||
|
||||
|
||||
## [v0.51.104] — 2026-05-21 — Release CB (stage-397 — 9-PR batch — i18n zh-CN/zh-TW cron status + geist-contrast skin polish + tablet hardware Enter + stale Codex slash model state + SSE reconnect jitter + cron run inline expansion + inflight send race + new-chat model provider sync + virtualized sidebar scroll-clamp resync + transcript cache invalidation on same-count content)
|
||||
|
||||
|
||||
@@ -4311,6 +4311,7 @@ _SETTINGS_DEFAULTS = {
|
||||
"send_key": "enter", # 'enter' or 'ctrl+enter'
|
||||
"show_token_usage": False, # show input/output token badge below assistant messages
|
||||
"show_quota_chip": False, # show ambient provider quota chip in composer footer (default off; wide desktop only when enabled, see style.css @media)
|
||||
"hide_empty_state_suggestions": False, # hide the default new-chat suggestion buttons
|
||||
"show_tps": False, # show tokens-per-second chip in assistant message headers
|
||||
"fade_text_effect": False, # animate newly streamed words with a lightweight fade-in effect
|
||||
"show_cli_sessions": False, # merge CLI sessions from state.db into the sidebar
|
||||
@@ -4455,6 +4456,7 @@ _SETTINGS_BOOL_KEYS = {
|
||||
"onboarding_completed",
|
||||
"show_token_usage",
|
||||
"show_quota_chip",
|
||||
"hide_empty_state_suggestions",
|
||||
"show_tps",
|
||||
"fade_text_effect",
|
||||
"show_cli_sessions",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
@@ -1152,6 +1152,11 @@ document.querySelectorAll('.suggestion').forEach(btn=>{
|
||||
btn.onclick=()=>{$('msg').value=btn.dataset.msg;send();};
|
||||
});
|
||||
|
||||
function applyEmptyStateSuggestionPref(){
|
||||
if(!$('emptyState')) return;
|
||||
$('emptyState').classList.toggle('no-suggestions',window._hideEmptyStateSuggestions===true);
|
||||
}
|
||||
|
||||
window.addEventListener('resize',()=>{
|
||||
_syncWorkspacePanelInlineWidth();
|
||||
syncWorkspacePanelState();
|
||||
@@ -1431,6 +1436,8 @@ function applyBotName(){
|
||||
window._sendKey=s.send_key||'enter';
|
||||
window._showTokenUsage=!!s.show_token_usage;
|
||||
window._showQuotaChip=s.show_quota_chip===true;
|
||||
window._hideEmptyStateSuggestions=s.hide_empty_state_suggestions===true;
|
||||
applyEmptyStateSuggestionPref();
|
||||
window._showTps=!!s.show_tps;
|
||||
window._fadeTextEffect=!!s.fade_text_effect;
|
||||
window._showCliSessions=!!s.show_cli_sessions;
|
||||
@@ -1520,6 +1527,8 @@ function applyBotName(){
|
||||
window._sendKey='enter';
|
||||
window._showTokenUsage=false;
|
||||
window._showQuotaChip=false;
|
||||
window._hideEmptyStateSuggestions=false;
|
||||
applyEmptyStateSuggestionPref();
|
||||
window._showTps=false;
|
||||
window._fadeTextEffect=false;
|
||||
window._showCliSessions=false;
|
||||
|
||||
@@ -556,6 +556,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Language',
|
||||
settings_label_quota_chip: 'Show provider quota chip in composer',
|
||||
settings_desc_quota_chip: 'Displays an ambient remaining-quota indicator (e.g. OpenRouter credit balance) in the composer footer. Default off. Only visible on wide displays (≥1400px) when enabled, to keep the composer uncluttered on laptop and standard desktop widths.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Show token usage',
|
||||
settings_label_sidebar_density: 'Sidebar density',
|
||||
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
|
||||
@@ -1785,6 +1787,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Lingua',
|
||||
settings_label_quota_chip: 'Mostra il chip della quota del provider nel compositore',
|
||||
settings_desc_quota_chip: "Mostra un indicatore di quota residua (es. saldo crediti OpenRouter) nel piè di pagina del compositore. Predefinito disattivato. Visibile solo su schermi larghi (≥1400px) quando attivato, per mantenere il compositore non affollato su laptop e desktop standard.",
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Mostra uso token',
|
||||
settings_label_sidebar_density: 'Densità sidebar',
|
||||
cmd_reasoning: 'Mostra/nascondi ragionamento, imposta livello sforzo o controlla stato attuale',
|
||||
@@ -3006,6 +3010,8 @@ const LOCALES = {
|
||||
settings_label_language: '言語',
|
||||
settings_label_quota_chip: 'コンポーザーにプロバイダーのクォータチップを表示',
|
||||
settings_desc_quota_chip: 'コンポーザーのフッターに残りクォータインジケーター(例: OpenRouter のクレジット残高)を表示します。デフォルトはオフ。有効にした場合、ラップトップや標準デスクトップの幅でコンポーザーが混雑しないよう、ワイドディスプレイ(≥1400px)でのみ表示されます。',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'トークン使用量を表示',
|
||||
settings_label_sidebar_density: 'サイドバー密度',
|
||||
cmd_reasoning: '思考表示の切り替え (表示/非表示)、努力レベル設定、現在状態の確認',
|
||||
@@ -4033,6 +4039,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Язык',
|
||||
settings_label_quota_chip: 'Показывать чип квоты провайдера в композиторе',
|
||||
settings_desc_quota_chip: 'Отображает фоновый индикатор остатка квоты (например, баланс кредитов OpenRouter) в подвале композитора. По умолчанию отключено. Виден только на широких экранах (≥1400px) при включении, чтобы не загромождать композитор на ноутбуках и стандартных мониторах.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Показывать использование токенов',
|
||||
settings_label_sidebar_density: 'Плотность боковой панели',
|
||||
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
|
||||
@@ -5183,6 +5191,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Idioma',
|
||||
settings_label_quota_chip: 'Mostrar el chip de cuota del proveedor en el compositor',
|
||||
settings_desc_quota_chip: 'Muestra un indicador ambiental de cuota restante (por ejemplo, saldo de crédito de OpenRouter) en el pie del compositor. Predeterminado: desactivado. Solo visible en pantallas anchas (≥1400px) cuando se activa, para mantener el compositor despejado en portátiles y monitores estándar.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Mostrar uso de tokens',
|
||||
settings_label_sidebar_density: 'Densidad de la barra lateral',
|
||||
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
|
||||
@@ -6326,6 +6336,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Sprache',
|
||||
settings_label_quota_chip: 'Anbieter-Kontingent-Chip im Editor anzeigen',
|
||||
settings_desc_quota_chip: 'Zeigt einen Hintergrund-Indikator des verbleibenden Kontingents (z. B. OpenRouter-Guthaben) in der Editor-Fußzeile an. Standardmäßig deaktiviert. Bei Aktivierung nur auf breiten Bildschirmen (≥1400px) sichtbar, damit der Editor auf Laptops und Standard-Desktops übersichtlich bleibt.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Token-Verbrauch anzeigen',
|
||||
settings_label_sidebar_density: 'Seitenleistendichte',
|
||||
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
|
||||
@@ -7521,6 +7533,8 @@ const LOCALES = {
|
||||
settings_label_language: '语言',
|
||||
settings_label_quota_chip: '在编辑器中显示供应商配额标签',
|
||||
settings_desc_quota_chip: '在编辑器底部显示剩余配额指示器(如 OpenRouter 信用余额)。默认关闭。启用时仅在宽屏(≥1400px)显示,以保持笔记本和标准桌面屏幕上编辑器的整洁。',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: '显示 token 用量',
|
||||
settings_label_sidebar_density: '侧边栏密度',
|
||||
cmd_reasoning: '切换思维可见性(显示/隐藏)、设置工作强度或查看当前状态',
|
||||
@@ -8693,6 +8707,8 @@ const LOCALES = {
|
||||
settings_label_language: '\u8a9e\u8a00',
|
||||
settings_label_quota_chip: '在編輯器中顯示供應商配額標籤',
|
||||
settings_desc_quota_chip: '在編輯器底部顯示剩餘配額指示器(如 OpenRouter 點數餘額)。預設關閉。啟用時僅在寬螢幕(≥1400px)顯示,以保持筆記型電腦和標準桌面螢幕上編輯器的整潔。',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: '\u986f\u793a token \u7528\u91cf',
|
||||
settings_label_sidebar_density: '側邊欄密度',
|
||||
cmd_reasoning: '切換思考區塊可見性(顯示/隱藏)或設定努力等級',
|
||||
@@ -10000,6 +10016,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Idioma',
|
||||
settings_label_quota_chip: 'Mostrar o chip de cota do provedor no compositor',
|
||||
settings_desc_quota_chip: 'Exibe um indicador ambiente de cota restante (por exemplo, saldo de crédito do OpenRouter) no rodapé do compositor. Desativado por padrão. Visível apenas em telas largas (≥1400px) quando ativado, para manter o compositor livre em laptops e monitores padrão.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Mostrar uso de tokens',
|
||||
settings_label_sidebar_density: 'Densidade da sidebar',
|
||||
cmd_reasoning: 'Alternar visibilidade do pensamento (mostrar/ocultar)',
|
||||
@@ -11124,6 +11142,8 @@ const LOCALES = {
|
||||
settings_label_language: '언어',
|
||||
settings_label_quota_chip: '작성기에 공급자 할당량 칩 표시',
|
||||
settings_desc_quota_chip: '작성기 푸터에 남은 할당량 표시기(예: OpenRouter 크레딧 잔액)를 표시합니다. 기본값은 끔. 활성화 시 노트북과 표준 데스크톱에서 작성기가 복잡해지지 않도록 와이드 디스플레이(≥1400px)에서만 표시됩니다.',
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: '토큰 사용량 표시',
|
||||
settings_label_sidebar_density: '사이드바 밀도',
|
||||
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
|
||||
@@ -12263,6 +12283,8 @@ const LOCALES = {
|
||||
settings_label_language: 'Langue',
|
||||
settings_label_quota_chip: 'Afficher la pastille de quota du fournisseur dans le compositeur',
|
||||
settings_desc_quota_chip: "Affiche un indicateur ambiant de quota restant (par ex. solde de crédit OpenRouter) dans le pied du compositeur. Désactivé par défaut. Visible uniquement sur les écrans larges (≥1400px) lorsqu'activé, pour garder le compositeur dégagé sur les ordinateurs portables et les bureaux standard.",
|
||||
settings_label_hide_suggestions: 'Hide new-chat suggestions',
|
||||
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
|
||||
settings_label_token_usage: 'Afficher l\'utilisation du jeton',
|
||||
settings_label_sidebar_density: 'Densité de la barre latérale',
|
||||
cmd_reasoning: 'Basculez la visibilité de la réflexion (afficher/masquer), définir le niveau d\'effort ou vérifier l\'état actuel',
|
||||
|
||||
@@ -995,6 +995,13 @@
|
||||
<select id="settingsModel" style="width:100%;padding:8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px"></select>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_model">Used for new conversations. Existing conversations keep their selected model.</div>
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
|
||||
<input type="checkbox" id="settingsHideSuggestions" style="width:15px;height:15px;accent-color:var(--accent)">
|
||||
<span data-i18n="settings_label_hide_suggestions">Hide new-chat suggestions</span>
|
||||
</label>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_hide_suggestions">Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.</div>
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label for="settingsSendKey" data-i18n="settings_label_send_key">Send Key</label>
|
||||
<select id="settingsSendKey" style="width:100%;padding:8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px">
|
||||
|
||||
@@ -5414,6 +5414,8 @@ function _preferencesPayloadFromUi(){
|
||||
if(showUsageCb) payload.show_token_usage=showUsageCb.checked;
|
||||
const showQuotaChipCb=$('settingsShowQuotaChip');
|
||||
if(showQuotaChipCb) payload.show_quota_chip=showQuotaChipCb.checked;
|
||||
const hideSuggestionsCb=$('settingsHideSuggestions');
|
||||
if(hideSuggestionsCb) payload.hide_empty_state_suggestions=hideSuggestionsCb.checked;
|
||||
const showTpsCb=$('settingsShowTps');
|
||||
if(showTpsCb) payload.show_tps=showTpsCb.checked;
|
||||
const fadeTextCb=$('settingsFadeTextEffect');
|
||||
@@ -5496,6 +5498,10 @@ async function _autosavePreferencesSettings(payload){
|
||||
if(typeof clearMessageRenderCache==='function') clearMessageRenderCache();
|
||||
if(typeof renderMessages==='function') renderMessages();
|
||||
}
|
||||
if(payload&&payload.hide_empty_state_suggestions!==undefined){
|
||||
window._hideEmptyStateSuggestions=!!(saved&&saved.hide_empty_state_suggestions);
|
||||
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
|
||||
}
|
||||
_settingsPreferencesAutosaveRetryPayload=null;
|
||||
_setPreferencesAutosaveStatus('saved');
|
||||
// Only clear the global dirty flag and hide the unsaved-changes bar when
|
||||
@@ -5680,6 +5686,17 @@ async function loadSettingsPanel(){
|
||||
_schedulePreferencesAutosave();
|
||||
},{once:false});
|
||||
}
|
||||
const hideSuggestionsCb=$('settingsHideSuggestions');
|
||||
if(hideSuggestionsCb){
|
||||
hideSuggestionsCb.checked=settings.hide_empty_state_suggestions===true;
|
||||
window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;
|
||||
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
|
||||
hideSuggestionsCb.addEventListener('change',()=>{
|
||||
window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;
|
||||
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
|
||||
_schedulePreferencesAutosave();
|
||||
},{once:false});
|
||||
}
|
||||
const showTpsCb=$('settingsShowTps');
|
||||
if(showTpsCb){showTpsCb.checked=!!settings.show_tps;showTpsCb.addEventListener('change',_schedulePreferencesAutosave,{once:false});}
|
||||
const fadeTextCb=$('settingsFadeTextEffect');
|
||||
|
||||
@@ -1283,6 +1283,7 @@
|
||||
.dot:nth-child(2){animation-delay:.22s;}.dot:nth-child(3){animation-delay:.44s;}
|
||||
@keyframes pulse{0%,80%,100%{opacity:.2;transform:scale(.8)}40%{opacity:.8;transform:scale(1)}}
|
||||
.empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px;color:var(--muted);}
|
||||
.empty-state.no-suggestions .suggestion-grid{display:none}
|
||||
.empty-logo{width:64px;height:64px;border-radius:20px;background:linear-gradient(145deg,var(--accent-bg),var(--accent-bg));border:1px solid var(--accent-bg);display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:700;color:var(--accent-text);margin-bottom:4px;box-shadow:0 4px 20px var(--accent-bg);}
|
||||
.empty-state h2{font-size:20px;color:var(--text);font-weight:700;letter-spacing:-.02em;}
|
||||
.empty-state p{font-size:14px;text-align:center;max-width:320px;}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
"""Regression coverage for #2679: optional hiding of empty-chat suggestions."""
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
INDEX = REPO_ROOT / "static" / "index.html"
|
||||
STYLE = REPO_ROOT / "static" / "style.css"
|
||||
PANELS = REPO_ROOT / "static" / "panels.js"
|
||||
BOOT = REPO_ROOT / "static" / "boot.js"
|
||||
I18N = REPO_ROOT / "static" / "i18n.js"
|
||||
CONFIG = REPO_ROOT / "api" / "config.py"
|
||||
CHANGELOG = REPO_ROOT / "CHANGELOG.md"
|
||||
|
||||
|
||||
def test_hide_suggestions_setting_is_default_off_and_allowed():
|
||||
src = CONFIG.read_text(encoding="utf-8")
|
||||
assert '"hide_empty_state_suggestions": False' in src
|
||||
assert '"hide_empty_state_suggestions",' in src
|
||||
|
||||
|
||||
def test_settings_preferences_expose_hide_suggestions_toggle():
|
||||
html = INDEX.read_text(encoding="utf-8")
|
||||
assert 'id="settingsHideSuggestions"' in html
|
||||
assert 'data-i18n="settings_label_hide_suggestions"' in html
|
||||
assert 'data-i18n="settings_desc_hide_suggestions"' in html
|
||||
|
||||
|
||||
def test_empty_state_has_hideable_suggestions_hook_and_css():
|
||||
html = INDEX.read_text(encoding="utf-8")
|
||||
css = STYLE.read_text(encoding="utf-8")
|
||||
assert 'class="suggestion-grid"' in html
|
||||
assert '.empty-state.no-suggestions .suggestion-grid{display:none}' in css
|
||||
|
||||
|
||||
def test_boot_applies_saved_hide_suggestions_preference():
|
||||
js = BOOT.read_text(encoding="utf-8")
|
||||
assert "function applyEmptyStateSuggestionPref()" in js
|
||||
assert "window._hideEmptyStateSuggestions=s.hide_empty_state_suggestions===true" in js
|
||||
assert "window._hideEmptyStateSuggestions=false" in js
|
||||
assert "$('emptyState').classList.toggle('no-suggestions',window._hideEmptyStateSuggestions===true)" in js
|
||||
|
||||
|
||||
def test_panels_round_trip_and_hot_apply_hide_suggestions():
|
||||
js = PANELS.read_text(encoding="utf-8")
|
||||
assert "const hideSuggestionsCb=$('settingsHideSuggestions');" in js
|
||||
assert "payload.hide_empty_state_suggestions=hideSuggestionsCb.checked;" in js
|
||||
assert "hideSuggestionsCb.checked=settings.hide_empty_state_suggestions===true;" in js
|
||||
assert "window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;" in js
|
||||
assert "if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();" in js
|
||||
|
||||
|
||||
def test_hide_suggestions_i18n_all_locales_and_changelog():
|
||||
js = I18N.read_text(encoding="utf-8")
|
||||
assert js.count("settings_label_hide_suggestions:") == 11
|
||||
assert js.count("settings_desc_hide_suggestions:") == 11
|
||||
changelog = CHANGELOG.read_text(encoding="utf-8")
|
||||
assert "#2679" in changelog
|
||||
assert "hide_empty_state_suggestions" in changelog
|
||||
Reference in new issue
Block a user