feat(sidebar): add show_kanban_sessions toggle to hide kanban worker sessions (#6780)

* feat(sidebar): add show_kanban_sessions toggle to hide kanban worker sessions

* fix(sidebar): kanban source-filter override + filtered-view cap (cron/webhook parity)

Gate re-review (Codex) found the kanban-hide addition missed cron/webhook
parity for the source-filter case:
- An explicit kanban source_filter now overrides the default hide (threaded
  source_filter into _dedupe_cli_sidebar_sessions_for_api, normalized with
  strip().lower() to match the loader), so a deliberate kanban view shows
  those rows even with the toggle off. Scoped to the matching source only.
- A dedicated KANBAN_PROJECT_CHIP_LIMIT bounds a filtered kanban-only view,
  mirroring CRON/WEBHOOK_PROJECT_CHIP_LIMIT.

Deliberately NOT changing the general exclude_sources: the original PR lets
kanban load on the source_filter=None path so the toggle-ON case works (the
hide is applied by _hide_from_default_sidebar only when the toggle is off).
Excluding kanban there would save the 20-row budget but break toggle-on
unless a bounded kanban merge is added (cron/webhook don't do that either) —
that query-budget optimization is deferred as a separate cross-cutting change.
The pinned-survives-hide finding is also out of scope (cron/webhook hide pinned
identically, confirmed by Codex). Adds bite-tested regressions.

Co-authored-by: vduke <vduke@users.noreply.github.com>

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
This commit is contained in:
Vincent Dukeandnesquena-hermes authored and GitHub committed 2026-08-09 02:53:25 +00:00
1 parent eb04bf5951
commit 64c2c12df7
9 files changed
+217 -3

No files matched your search

+4 -1
View File
@@ -60,6 +60,7 @@ SOURCE_LABELS = {
'cron': 'Cron',
'discord': 'Discord',
'email': 'Email',
'kanban': 'Kanban',
'wecom': 'WeCom',
'wecom_callback': 'WeCom Callback',
'slack': 'Slack',
@@ -97,6 +98,8 @@ def normalize_agent_session_source(raw_source: str | None) -> dict:
session_source = 'cron'
elif raw == 'webhook':
session_source = 'webhook'
elif raw == 'kanban':
session_source = 'kanban'
elif raw == 'tool':
session_source = 'tool'
elif raw == 'api_server':
@@ -220,7 +223,7 @@ def is_cli_session_row(row: dict) -> bool:
# runner, never a writable WebUI/CLI session (#5307). Classify it non-CLI so
# sidebar rows and every is_cli_session_row() consumer keep it out of the
# CLI/writable treatment.
non_cli_sources = MESSAGING_SOURCES | {"cron", "webhook", "tool", "api", "api_server", "subagent"}
non_cli_sources = MESSAGING_SOURCES | {"cron", "webhook", "kanban", "tool", "api", "api_server", "subagent"}
if {source, source_tag, raw_source, source_name, source_label} & non_cli_sources:
return False
if source == "messaging":
+2
View File
@@ -9276,6 +9276,7 @@ _SETTINGS_DEFAULTS = {
"show_claude_code_sessions": True, # allow filtering Claude Code rows without hiding other imported sources
"show_cron_sessions": False, # surface cron sessions in the sidebar (subordinate to show_cli_sessions)
"show_webhook_sessions": False, # surface webhook sessions in the sidebar (subordinate to show_cli_sessions)
"show_kanban_sessions": False, # surface kanban worker sessions in the sidebar (subordinate to show_cli_sessions)
"show_previous_messaging_sessions": False, # show older Telegram/Discord/etc. reset segments
"sync_to_insights": False, # mirror WebUI token usage to state.db for /insights
"check_for_updates": True, # check if webui/agent repos are behind upstream
@@ -9620,6 +9621,7 @@ _SETTINGS_BOOL_KEYS = {
"show_claude_code_sessions",
"show_cron_sessions",
"show_webhook_sessions",
"show_kanban_sessions",
"show_previous_messaging_sessions",
"sync_to_insights",
"check_for_updates",
+9 -2
View File
@@ -52,6 +52,10 @@ CLI_VISIBLE_SESSION_LIMIT = 20
# sidebar window (#3172).
CRON_PROJECT_CHIP_LIMIT = 200
WEBHOOK_PROJECT_CHIP_LIMIT = 200
# Kanban worker runs are internal/background like cron+webhook; keep the same
# higher project-chip cap so project-assigned kanban rows stay addressable when
# the toggle is on, without letting them dominate the default sidebar window.
KANBAN_PROJECT_CHIP_LIMIT = 200
_CLI_SESSIONS_CACHE_TTL_SECONDS = 5.0
# While a turn is actively streaming, hold the CLI/cron projection longer than
# one poll interval (mirrors the route-level #4808 hold-down). The frontend
@@ -4976,7 +4980,7 @@ def new_session(workspace=None, model=None, profile=None, model_provider=None, p
s.save()
return s
def _hide_from_default_sidebar(session: dict, *, show_cron: bool = False, show_webhook: bool = False) -> bool:
def _hide_from_default_sidebar(session: dict, *, show_cron: bool = False, show_webhook: bool = False, show_kanban: bool = False) -> bool:
"""Return True for internal/background sessions hidden from the default list."""
sid = str(session.get('session_id') or '')
source = (
@@ -4989,6 +4993,8 @@ def _hide_from_default_sidebar(session: dict, *, show_cron: bool = False, show_w
return True
if not show_webhook and source == 'webhook':
return True
if not show_kanban and source == 'kanban':
return True
if bool(session.get('pre_compression_snapshot')):
return not bool(session.get('_show_pre_compression_snapshot'))
return False
@@ -5042,7 +5048,7 @@ def _is_intentionally_background_sidebar_session(session: dict) -> bool:
or session.get('raw_source')
or session.get('session_source')
)
return source in {'cron', 'webhook'} or sid.startswith('cron_')
return source in {'cron', 'webhook', 'kanban'} or sid.startswith('cron_')
def _include_project_hidden_background_sidebar_sessions(
@@ -7543,6 +7549,7 @@ def _load_cli_sessions_uncached(
limit=visible_session_limit if visible_session_limit is not None else (
CRON_PROJECT_CHIP_LIMIT if source_filter == 'cron'
else WEBHOOK_PROJECT_CHIP_LIMIT if source_filter == 'webhook'
else KANBAN_PROJECT_CHIP_LIMIT if source_filter == 'kanban'
else CLI_VISIBLE_SESSION_LIMIT
),
log=logger,
+2
View File
@@ -127,6 +127,7 @@ def _session_list_cache_key(
exclude_hidden: bool = False,
visible_only: bool = False,
show_webhook_sessions: bool = False,
show_kanban_sessions: bool = False,
source_filter: str | None = None,
sidebar_source: str | None = None,
archived_limit: int | None = None,
@@ -152,6 +153,7 @@ def _session_list_cache_key(
bool(exclude_hidden),
bool(visible_only),
bool(show_webhook_sessions),
bool(show_kanban_sessions),
source_filter,
sidebar_source,
normalized_archived_limit,
+28
View File
@@ -1942,6 +1942,7 @@ def _session_list_cache_key(
exclude_hidden: bool = False,
visible_only: bool = False,
show_webhook_sessions: bool = False,
show_kanban_sessions: bool = False,
source_filter: str | None = None,
sidebar_source: str | None = None,
archived_limit: int | None = None,
@@ -1958,6 +1959,7 @@ def _session_list_cache_key(
exclude_hidden=exclude_hidden,
visible_only=visible_only,
show_webhook_sessions=show_webhook_sessions,
show_kanban_sessions=show_kanban_sessions,
source_filter=source_filter,
sidebar_source=sidebar_source,
archived_limit=archived_limit,
@@ -2203,6 +2205,7 @@ def _build_session_list_cache_payload(
exclude_hidden: bool = False,
visible_only: bool = False,
show_webhook_sessions: bool = False,
show_kanban_sessions: bool = False,
source_filter: str | None = None,
sidebar_source: str | None = None,
archived_limit: int | None = None,
@@ -2254,6 +2257,7 @@ def _build_session_list_cache_payload(
show_previous_messaging_sessions = bool(show_previous_messaging_sessions)
show_cron_sessions = bool(show_cron_sessions)
show_webhook_sessions = bool(show_webhook_sessions)
show_kanban_sessions = bool(show_kanban_sessions)
webui_sessions = [_normalize_sidebar_source_flags(s) for s in webui_sessions]
if show_cli_sessions:
diag_stage("get_cli_sessions")
@@ -2400,6 +2404,8 @@ def _build_session_list_cache_payload(
represented_webui_ids,
show_cron_sessions=show_cron_sessions,
show_webhook_sessions=show_webhook_sessions,
show_kanban_sessions=show_kanban_sessions,
source_filter=source_filter,
)
else:
diag_stage("filter_webui_sessions")
@@ -2573,6 +2579,7 @@ def _build_session_list_cache_payload(
"show_cron_sessions": show_cron_sessions,
"show_claude_code_sessions": show_claude_code_sessions if show_cli_sessions else False,
"show_webhook_sessions": show_webhook_sessions,
"show_kanban_sessions": show_kanban_sessions,
},
}
@@ -9405,6 +9412,8 @@ def _dedupe_cli_sidebar_sessions_for_api(
*,
show_cron_sessions: bool = False,
show_webhook_sessions: bool = False,
show_kanban_sessions: bool = False,
source_filter: str | None = None,
) -> list[dict]:
"""Return state sidebar rows while preserving project-hidden background rows.
@@ -9412,12 +9421,26 @@ def _dedupe_cli_sidebar_sessions_for_api(
session store. They should stay hidden from the default sidebar, but
project-assigned messageful rows must remain in the `/api/sessions` payload
with `default_hidden` so the matching project chip can reveal them (#3134).
An explicit ``source_filter`` for a background source (cron/webhook/kanban)
is a deliberate request to view those rows, so it overrides the default
hide for that source only — the user asked for them.
"""
from api.models import (
_hide_from_default_sidebar as _hide_background,
_include_project_hidden_background_sidebar_sessions,
)
# An explicit background source filter reveals that source (override the hide).
# Normalize to match how the loader canonicalizes source_filter (strip+lower).
_sf = str(source_filter or '').strip().lower()
if _sf == 'cron':
show_cron_sessions = True
elif _sf == 'webhook':
show_webhook_sessions = True
elif _sf == 'kanban':
show_kanban_sessions = True
candidates = [
s for s in cli
if s["session_id"] not in represented_webui_ids
@@ -9430,6 +9453,7 @@ def _dedupe_cli_sidebar_sessions_for_api(
s,
show_cron=show_cron_sessions,
show_webhook=show_webhook_sessions,
show_kanban=show_kanban_sessions,
)
]
return _include_project_hidden_background_sidebar_sessions(candidates, visible)
@@ -13320,6 +13344,7 @@ def handle_get(handler, parsed) -> bool:
)
show_cron_sessions = bool(settings.get("show_cron_sessions"))
show_webhook_sessions = bool(settings.get("show_webhook_sessions"))
show_kanban_sessions = bool(settings.get("show_kanban_sessions"))
agent_session_source_filter = settings.get("agent_session_source_filter")
active_profile = profiles_api.get_active_profile_name()
all_profiles = _all_profiles_enabled(parsed)
@@ -13343,6 +13368,7 @@ def handle_get(handler, parsed) -> bool:
exclude_hidden=exclude_hidden,
visible_only=True,
show_webhook_sessions=show_webhook_sessions,
show_kanban_sessions=show_kanban_sessions,
source_filter=agent_session_source_filter,
sidebar_source=sidebar_source,
archived_limit=archived_limit,
@@ -13365,6 +13391,7 @@ def handle_get(handler, parsed) -> bool:
exclude_hidden=exclude_hidden,
visible_only=True,
show_webhook_sessions=show_webhook_sessions,
show_kanban_sessions=show_kanban_sessions,
source_filter=agent_session_source_filter,
sidebar_source=sidebar_source,
archived_limit=archived_limit,
@@ -16001,6 +16028,7 @@ def handle_post(handler, parsed) -> bool:
"show_claude_code_sessions",
"show_cron_sessions",
"show_webhook_sessions",
"show_kanban_sessions",
"show_previous_messaging_sessions",
)
):
+30
View File
@@ -890,6 +890,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Show kanban sessions',
settings_label_previous_messaging_sessions: 'Show previous messaging sessions',
settings_label_sync_insights: 'Sync to insights',
settings_label_check_updates: 'Check for updates',
@@ -1223,6 +1224,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Surface kanban worker runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; worker runs are internal and can flood the sidebar.',
settings_desc_previous_messaging_sessions: 'Show older Discord, Telegram, Slack, and Weixin sessions that were replaced by reset or compression.',
settings_desc_sync_insights: 'Mirrors WebUI token usage to state.db so hermes /insights includes browser session data. Off by default.',
settings_desc_check_updates: 'Show a banner when newer versions of the WebUI or Agent are available. Runs a background git fetch periodically.',
@@ -2652,6 +2654,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Mostra sessioni kanban',
settings_label_previous_messaging_sessions: 'Mostra sessioni di messaggistica precedenti',
settings_label_sync_insights: 'Sincronizza con insights',
settings_label_check_updates: 'Verifica aggiornamenti',
@@ -2973,6 +2976,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Mostra le esecuzioni dei worker kanban come conversazioni nella barra laterale. Attivo solo quando le sessioni non-WebUI sono abilitate. Disattivato per impostazione predefinita; le esecuzioni dei worker sono interne e possono inondare la barra laterale.',
settings_desc_previous_messaging_sessions: 'Mostra sessioni Discord, Telegram, Slack e Weixin più vecchie sostituite da reset o compressione.',
settings_desc_sync_insights: 'Rispecchia l\'uso token WebUI su state.db così hermes /insights include i dati delle sessioni browser. Disattivato per impostazione predefinita.',
settings_desc_check_updates: 'Mostra un banner quando sono disponibili versioni più recenti della WebUI o dell\'Agente. Esegue un git fetch in background periodicamente.',
@@ -4397,6 +4401,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Claude Code セッションを表示',
settings_label_cron_sessions: 'Cronセッションを表示',
settings_label_webhook_sessions: 'Webhookセッションを表示',
settings_label_kanban_sessions: 'Kanbanセッションを表示',
settings_label_previous_messaging_sessions: '以前のメッセージングセッションを表示',
settings_label_sync_insights: 'インサイトに同期',
settings_label_check_updates: 'アップデートを確認',
@@ -4723,6 +4728,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'サイドバーに Claude Code からインポートされたセッションを表示します。または、他の外部セッションは表示したまま Claude Code のセッションのみを非表示にします。',
settings_desc_cron_sessions: 'Cronジョブの出力をサイドバーの会話として表示します。WebUI以外のセッションが有効な場合のみ機能します。デフォルトはオフ。高頻度のジョブはサイドバーを溢れさせる可能性があります。',
settings_desc_webhook_sessions: 'Webhook実行をサイドバーの会話として表示します。WebUI以外のセッションが有効な場合のみ機能します。デフォルトはオフ。高頻度のルートはサイドバーを溢れさせる可能性があります。',
settings_desc_kanban_sessions: 'Kanbanワーカーの実行をサイドバーの会話として表示します。WebUI以外のセッションが有効な場合のみ機能します。デフォルトはオフ。ワーカー実行は内部的なもので、サイドバーを溢れさせる可能性があります。',
settings_desc_previous_messaging_sessions: 'reset または compression によって置き換えられた以前の Discord、Telegram、Slack、Weixin セッションを表示します。',
settings_desc_sync_insights: 'WebUI のトークン使用量を state.db にミラーし、hermes /insights にブラウザセッションのデータを含めます。デフォルトはオフ。',
settings_desc_check_updates: 'WebUI または Agent の新しいバージョンが利用可能な時にバナーを表示します。バックグラウンドで定期的に git fetch を実行します。',
@@ -5846,6 +5852,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Показывать сеансы Claude Code',
settings_label_cron_sessions: 'Показывать cron-сеансы',
settings_label_webhook_sessions: 'Показывать webhook-сеансы',
settings_label_kanban_sessions: 'Показывать kanban-сеансы',
settings_label_previous_messaging_sessions: 'Показывать предыдущие сеансы обмена сообщениями',
settings_label_sync_insights: 'Синхронизировать с Insights',
settings_label_check_updates: 'Проверять обновления',
@@ -6097,6 +6104,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Показывать импортированные сеансы Claude Code в боковой панели или скрывать их, оставляя другие внешние сеансы видимыми.',
settings_desc_cron_sessions: 'Показывать вывод cron-заданий как беседы в боковой панели. Работает только при включённых не-WebUI сеансах. По умолчанию выключено; частые задания могут переполнить боковую панель.',
settings_desc_webhook_sessions: 'Показывать запуски webhook как беседы в боковой панели. Работает только при включённых не-WebUI сеансах. По умолчанию выключено; высокочастотные маршруты могут переполнить боковую панель.',
settings_desc_kanban_sessions: 'Показывать запуски kanban-воркеров как беседы в боковой панели. Работает только при включённых не-WebUI сеансах. По умолчанию выключено; запуски воркеров — внутренние и могут переполнить боковую панель.',
settings_desc_previous_messaging_sessions: 'Показывать предыдущие сеансы Discord, Telegram, Slack и Weixin, замененные сбросом или сжатием.',
settings_desc_sync_insights: 'Синхронизирует использование токенов WebUI в state.db, чтобы Hermes /insights включал данные браузерных сеансов. Выключено по умолчанию.',
settings_desc_check_updates: 'Показывает баннер, когда доступны более новые версии WebUI или Agent. Периодически выполняет git fetch в фоне.',
@@ -7544,6 +7552,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Mostrar sesiones kanban',
settings_label_previous_messaging_sessions: 'Mostrar sesiones de mensajería anteriores',
settings_label_sync_insights: 'Sincronizar con insights',
settings_label_check_updates: 'Buscar actualizaciones',
@@ -7806,6 +7815,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Mostrar las ejecuciones de los workers kanban como conversaciones en la barra lateral. Solo activo cuando las sesiones no-WebUI están habilitadas. Desactivado por defecto; las ejecuciones de workers son internas y pueden inundar la barra lateral.',
settings_desc_previous_messaging_sessions: 'Mostrar sesiones antiguas de Discord, Telegram, Slack y Weixin reemplazadas por reset o compresión.',
settings_desc_sync_insights: 'Refleja el uso de tokens de la WebUI en state.db para que hermes /insights incluya datos de sesiones del navegador. Desactivado por defecto.',
settings_desc_check_updates: 'Muestra un banner cuando haya versiones más nuevas de la WebUI o del Agent. Ejecuta periódicamente un git fetch en segundo plano.',
@@ -9211,6 +9221,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Kanban-Sitzungen anzeigen',
settings_label_previous_messaging_sessions: 'Vorherige Messaging-Sitzungen anzeigen',
settings_label_sync_insights: 'Mit Insights synchronisieren',
settings_label_check_updates: 'Nach Updates suchen',
@@ -9463,6 +9474,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Kanban-Worker-Läufe als Unterhaltungen in der Seitenleiste anzeigen. Nur aktiv, wenn Nicht-WebUI-Sitzungen aktiviert sind. Standardmäßig aus; Worker-Läufe sind intern und können die Seitenleiste überfluten.',
settings_desc_previous_messaging_sessions: 'Zeigt ältere Discord-, Telegram-, Slack- und Weixin-Sitzungen, die durch Reset oder Compression ersetzt wurden.',
settings_desc_sync_insights: 'Spiegelt den WebUI-Token-Verbrauch in die state.db, sodass hermes /insights Browser-Sitzungsdaten enthält. Standardmäßig aus.',
settings_desc_check_updates: 'Zeigt ein Banner an, wenn neuere Versionen der WebUI oder des Agenten verfügbar sind. Führt regelmäßig einen Git-Fetch im Hintergrund aus.',
@@ -10939,6 +10951,7 @@ const LOCALES = {
settings_label_claude_code_sessions: '显示 Claude Code 会话',
settings_label_cron_sessions: '显示定时任务会话',
settings_label_webhook_sessions: '显示Webhook会话',
settings_label_kanban_sessions: '显示Kanban会话',
settings_label_previous_messaging_sessions: '显示以前的消息会话',
settings_label_sync_insights: '同步到 insights',
settings_label_check_updates: '检查更新',
@@ -11283,6 +11296,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: '在侧边栏中显示已导入的Claude Code会话,或者隐藏它们,同时保持其他外部会话可见。',
settings_desc_cron_sessions: '将定时任务输出以对话形式显示在侧边栏。仅在启用非 WebUI 会话时此功能才会生效。默认关闭;高频任务可能会使侧边栏信息泛滥。',
settings_desc_webhook_sessions: '将Webhook运行情况以对话形式显示在侧边栏。仅在启用非 WebUI 会话时此功能才会生效。默认关闭;大量的路由信息可能会使侧边栏信息泛滥。',
settings_desc_kanban_sessions: '将Kanban工作线程的运行情况以对话形式显示在侧边栏。仅在启用非 WebUI 会话时此功能才会生效。默认关闭;工作线程运行是内部操作,可能会使侧边栏信息泛滥。',
settings_desc_previous_messaging_sessions: '显示被 reset 或 compression 替换的较旧的 Discord、Telegram、Slack 和 Weixin 会话。',
settings_desc_sync_insights: '将 WebUI token 使用情况同步到 state.db,使 hermes /insights 包含浏览器会话数据。默认关闭。',
settings_desc_check_updates: '当有更新的 WebUI 或助手版本时显示横幅。会在后台定期执行 git fetch。',
@@ -12920,6 +12934,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: '顯示Kanban工作階段',
settings_label_previous_messaging_sessions: '顯示以前的訊息對話',
settings_label_sync_insights: '同步至 insights',
settings_label_check_updates: '檢查更新',
@@ -13249,6 +13264,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: '將Kanban worker 的執行顯示為側邊欄中的對話。僅在啟用非 WebUI 工作階段時才有效。預設為關閉;worker 執行是內部的,可能會使側邊欄氾濫。',
settings_desc_previous_messaging_sessions: '顯示被 reset 或 compression 替換的較舊的 Discord、Telegram、Slack 和 Weixin 對話。',
settings_desc_sync_insights: '將 WebUI token 用量鏡射到 state.db,讓 hermes /insights 納入瀏覽器工作階段資料。預設為關閉。',
settings_desc_check_updates: '有較新版 WebUI 或 Agent 時顯示橫幅。系統會定期在背景執行 git fetch。',
@@ -14558,6 +14574,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Mostrar sessões kanban',
settings_label_previous_messaging_sessions: 'Mostrar sessões de mensagens anteriores',
settings_label_sync_insights: 'Sincronizar para insights',
settings_label_check_updates: 'Verificar atualizações',
@@ -14813,6 +14830,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Mostrar execuções dos workers kanban como conversas na barra lateral. Ativo apenas quando as sessões não-WebUI estão habilitadas. Desativado por padrão; execuções de workers são internas e podem inundar a barra lateral.',
settings_desc_previous_messaging_sessions: 'Mostrar sessões antigas de Discord, Telegram, Slack e Weixin substituídas por reset ou compressão.',
settings_desc_sync_insights: 'Espelha uso de tokens para state.db.',
settings_desc_check_updates: 'Mostrar banner quando versões mais novas estiverem disponíveis.',
@@ -16201,6 +16219,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Kanban 세션 표시',
settings_label_previous_messaging_sessions: '이전 메시징 세션 표시',
settings_label_sync_insights: 'Insights에 동기화',
settings_label_check_updates: '업데이트 확인',
@@ -16455,6 +16474,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Kanban 워커 실행을 사이드바의 대화로 표시합니다. 비 WebUI 세션이 활성화된 경우에만 작동합니다. 기본적으로 꺼져 있습니다. 워커 실행은 내부 작업이며 사이드바를 넘칠 수 있습니다.',
settings_desc_previous_messaging_sessions: 'reset 또는 compression으로 교체된 이전 Discord, Telegram, Slack, Weixin 세션을 표시합니다.',
settings_desc_sync_insights: 'WebUI 토큰 사용량을 state.db에 반영하여 hermes /insights에 브라우저 세션 데이터가 포함되도록 합니다. 기본값은 꺼짐입니다.',
settings_desc_check_updates: 'WebUI 또는 Agent의 새 버전이 있으면 배너를 표시합니다. 백그라운드에서 주기적으로 git fetch를 실행합니다.',
@@ -17960,6 +17980,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Afficher les sessions cron',
settings_label_webhook_sessions: 'Afficher les sessions webhook',
settings_label_kanban_sessions: 'Afficher les sessions kanban',
settings_label_previous_messaging_sessions: 'Afficher les sessions de messagerie précédentes',
settings_label_sync_insights: 'Synchroniser avec les analyses',
settings_label_check_updates: 'Vérifier les mises à jour',
@@ -18282,6 +18303,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Afficher les sorties des tâches cron comme des conversations dans la barre latérale. Uniquement actif lorsque les sessions non-WebUI sont activées. Désactivé par défaut ; les tâches à haute fréquence peuvent inonder la barre latérale.',
settings_desc_webhook_sessions: 'Afficher les exécutions webhook comme des conversations dans la barre latérale. Uniquement actif lorsque les sessions non-WebUI sont activées. Désactivé par défaut ; les routes à volume élevé peuvent inonder la barre latérale.',
settings_desc_kanban_sessions: 'Afficher les exécutions des workers kanban comme des conversations dans la barre latérale. Uniquement actif lorsque les sessions non-WebUI sont activées. Désactivé par défaut ; les exécutions de workers sont internes et peuvent inonder la barre latérale.',
settings_desc_previous_messaging_sessions: 'Afficher les anciennes sessions Discord, Telegram, Slack et Weixin qui ont été remplacées par une réinitialisation ou une compression.',
settings_desc_sync_insights: 'Replique l\'utilisation des jetons de l\'interface Web vers state.db afin que hermes /insights inclue les données des sessions du navigateur. Désactivé par défaut.',
settings_desc_check_updates: 'Afficher une bannière lorsque de nouvelles versions de l\'interface Web ou de l\'agent sont disponibles. Exécute périodiquement un git fetch en arrière-plan.',
@@ -19748,6 +19770,7 @@ const LOCALES = {
settings_desc_virtualize_transcript: 'Experimentální. Vykresluje pouze viditelnou část velmi dlouhých chat transcriptů (přes 80 zpráv) pro urychlení posouvání. Standardně vypnuto protože to může způsobit blikání při posouvání na dlouhých relacích s velkými bloky volání nástrojů. Zapněte to pro vyzkoušení; nechte vypnuté pro vykreslení celého transcriptu najednou (a tak vyhledávání prohlížeče (Ctrl+F) odpovídá celé konverzaci).',
settings_desc_voice_mode: 'Zobrazit tlačítko hlasového režimu (audio vlna) vedle mikrofonu pro diktování. Umožňuje mluvit přirozeně — Hermes automaticky odesílá po pauze a čte odpovědi nahlas. Vyžaduje prohlížeč který podporuje rozpoznávání řeči i TTS.',
settings_desc_webhook_sessions: 'Zobrazit webhook běhy jako konverzace v bočním panelu. Aktivní pouze když jsou povoleny externí relace. Standardně vypnuto; vysokoobjemové trasy mohou zaplavit boční panel.',
settings_desc_kanban_sessions: 'Zobrazit běhy kanban workerů jako konverzace v bočním panelu. Aktivní pouze když jsou povoleny externí relace. Standardně vypnuto; běhy workerů jsou interní a mohou zaplavit boční panel.',
settings_desc_whats_new_summary: 'Mění akci Co je nového z otevření raw diff první na generování krátkého lidsky čitelného souhrnu. Regulární srovnání diff zůstává dostupné po souhrnu.',
settings_desc_worklog_details_expanded_default: 'Když povoleno, detaily Worklog se začínají rozbalené tak aby byly viditelné nástroje, přemýšlení a karty pokroku bez dalšího kliknutí. Když vypnuto, detaily zůstávají sbalené standardně; manuální volby sbalení/rozbalení na úroveň tahu stále vyhrávají.',
settings_desc_workspace_panel_open: 'Když povoleno, panel pracovního prostoru / prohlížeč souborů se otevírá automaticky s každou novou relací. Stále ho můžete kdykoliv manuálně zavřít.',
@@ -19830,6 +19853,7 @@ const LOCALES = {
settings_label_virtualize_transcript: 'Virtualizovat dlouhé transcripty (experimentální)',
settings_label_voice_mode: 'Tlačítko hands-free hlasového režimu',
settings_label_webhook_sessions: 'Zobrazit webhook relace',
settings_label_kanban_sessions: 'Zobrazit kanban relace',
settings_label_whats_new_summary: 'Shrnout Co je nového s AI',
settings_label_worklog_details_expanded_default: 'Automaticky otevírat detaily Worklog',
settings_label_workspace_panel_open: 'Ve výchozím stavu otevřít panel pracovního prostoru',
@@ -21377,6 +21401,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Show cron sessions',
settings_label_webhook_sessions: 'Show webhook sessions',
settings_label_kanban_sessions: 'Kanban oturumlarını göster',
settings_label_previous_messaging_sessions: 'Önceki mesajlaşma oturumlarını göster',
settings_label_sync_insights: 'Analizlerle senkronize edin',
settings_label_check_updates: 'Güncellemeleri kontrol edin',
@@ -21630,6 +21655,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Surface cron job output as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-frequency jobs can flood the sidebar.',
settings_desc_webhook_sessions: 'Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.',
settings_desc_kanban_sessions: 'Kanban worker çalıştırmalarını kenar çubuğunda konuşmalar olarak göster. Yalnızca WebUI dışı oturumlar etkinleştirildiğinde aktif. Varsayılan olarak kapalı; worker çalıştırmaları dahili olup kenar çubuğunu doldurabilir.',
settings_desc_previous_messaging_sessions: 'Sıfırlama veya sıkıştırmayla değiştirilen eski Discord, Telegram, Slack ve Weixin oturumlarını gösterin.',
settings_desc_sync_insights: 'WebUI belirteci kullanımını state.db\'ye yansıtır, böylece hermes /insights tarayıcı oturum verilerini içerir. Varsayılan olarak kapalıdır.',
settings_desc_check_updates: 'WebUI veya Agent\'ın daha yeni sürümleri mevcut olduğunda bir banner gösterin. Periyodik olarak bir arka plan git getirme işlemi çalıştırır.',
@@ -23136,6 +23162,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Pokaż sesje cron',
settings_label_webhook_sessions: 'Pokaż sesje webhooków',
settings_label_kanban_sessions: 'Pokaż sesje kanban',
settings_label_previous_messaging_sessions: 'Pokaż poprzednie sesje komunikatorów',
settings_label_sync_insights: 'Synchronizuj z Insights',
settings_label_check_updates: 'Sprawdzaj aktualizacje',
@@ -23459,6 +23486,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Wyświetlaj wyjście zadań cron jako konwersacje na pasku bocznym. Aktywne tylko wtedy, gdy włączone są sesje spoza WebUI. Domyślnie wyłączone; zadania o wysokiej częstotliwości mogą zalać pasek boczny.',
settings_desc_webhook_sessions: 'Wyświetlaj uruchomienia webhooków jako konwersacje na pasku bocznym. Aktywne tylko wtedy, gdy włączone są sesje spoza WebUI. Domyślnie wyłączone; trasy o dużym natężeniu mogą zalać pasek boczny.',
settings_desc_kanban_sessions: 'Wyświetlaj uruchomienia workerów kanban jako konwersacje na pasku bocznym. Aktywne tylko wtedy, gdy włączone są sesje spoza WebUI. Domyślnie wyłączone; uruchomienia workerów są wewnętrzne i mogą zalać pasek boczny.',
settings_desc_previous_messaging_sessions: 'Pokaż starsze sesje z Discorda, Telegrama, Slacka i Weixin, które zostały zastąpione przez reset lub kompresję.',
settings_desc_sync_insights: 'Odzwierciedla zużycie tokenów WebUI w state.db, dzięki czemu hermes /insights uwzględnia dane sesji przeglądarki. Domyślnie wyłączone.',
settings_desc_check_updates: 'Pokaż baner, gdy dostępne są nowsze wersje WebUI lub Agenta. Okresowo uruchamia pobieranie git fetch w tle.',
@@ -24714,6 +24742,7 @@ const LOCALES = {
settings_label_claude_code_sessions: 'Show Claude Code sessions',
settings_label_cron_sessions: 'Hiện phiên cron',
settings_label_webhook_sessions: 'Hiện phiên webhook',
settings_label_kanban_sessions: 'Hiện phiên kanban',
settings_label_previous_messaging_sessions: 'Hiện các phiên nhắn tin trước đó',
settings_label_sync_insights: 'Đồng bộ sang insights',
settings_label_check_updates: 'Kiểm tra cập nhật',
@@ -25034,6 +25063,7 @@ const LOCALES = {
settings_desc_claude_code_sessions: 'Show Claude Code imported sessions in the sidebar, or hide them while leaving other external sessions visible.',
settings_desc_cron_sessions: 'Hiển thị output của cron job như các cuộc trò chuyện trong sidebar. Chỉ hoạt động khi bật phiên không phải WebUI. Mặc định tắt; job tần suất cao có thể làm sidebar bị ngập.',
settings_desc_webhook_sessions: 'Hiển thị các lần chạy webhook như các cuộc trò chuyện trong sidebar. Chỉ hoạt động khi bật phiên không phải WebUI. Mặc định tắt; route lưu lượng cao có thể làm sidebar bị ngập.',
settings_desc_kanban_sessions: 'Hiển thị các lần chạy của kanban worker như các cuộc trò chuyện trong sidebar. Chỉ hoạt động khi bật phiên không phải WebUI. Mặc định tắt; các lần chạy worker là nội bộ và có thể làm sidebar bị ngập.',
settings_desc_previous_messaging_sessions: 'Hiển thị các phiên Discord, Telegram, Slack và Weixin cũ đã bị thay thế bởi reset hoặc nén.',
settings_desc_sync_insights: 'Đồng bộ token usage của WebUI sang state.db để hermes /insights bao gồm dữ liệu phiên trình duyệt. Mặc định tắt.',
settings_desc_check_updates: 'Hiển thị banner khi có phiên bản mới của WebUI hoặc Agent. Định kỳ chạy git fetch nền.',
+7
View File
@@ -1414,6 +1414,13 @@
</label>
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_webhook_sessions">Surface webhook runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; high-volume routes can flood the sidebar.</div>
</div>
<div class="settings-field" id="settingsShowKanbanSessionsField" style="margin-left:24px">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="checkbox" id="settingsShowKanbanSessions" style="width:15px;height:15px;accent-color:var(--accent)">
<span data-i18n="settings_label_kanban_sessions">Show kanban sessions</span>
</label>
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_kanban_sessions">Surface kanban worker runs as conversations in the sidebar. Only active when non-WebUI sessions are enabled. Defaults off; worker runs are internal and can flood the sidebar.</div>
</div>
<div class="settings-field">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="checkbox" id="settingsShowPreviousMessagingSessions" style="width:15px;height:15px;accent-color:var(--accent)">
+11
View File
@@ -8678,6 +8678,8 @@ function _preferencesPayloadFromUi(){
if(showCronCb) payload.show_cron_sessions=!!(showCliCb&&showCliCb.checked&&showCronCb.checked);
const showWebhookCb=$('settingsShowWebhookSessions');
if(showWebhookCb) payload.show_webhook_sessions=!!(showCliCb&&showCliCb.checked&&showWebhookCb.checked);
const showKanbanCb=$('settingsShowKanbanSessions');
if(showKanbanCb) payload.show_kanban_sessions=!!(showCliCb&&showCliCb.checked&&showKanbanCb.checked);
const showPreviousMessagingCb=$('settingsShowPreviousMessagingSessions');
if(showPreviousMessagingCb) payload.show_previous_messaging_sessions=showPreviousMessagingCb.checked;
const syncCb=$('settingsSyncInsights');
@@ -9394,6 +9396,13 @@ async function loadSettingsPanel(){
showWebhookCb.addEventListener('change',_schedulePreferencesAutosave,{once:false});
if(showCliCb){showCliCb.addEventListener('change',function(){showWebhookCb.disabled=!showCliCb.checked;},{once:false});}
}
const showKanbanCb=$('settingsShowKanbanSessions');
if(showKanbanCb){
showKanbanCb.checked=!!settings.show_kanban_sessions;
showKanbanCb.disabled=showCliCb?!showCliCb.checked:true;
showKanbanCb.addEventListener('change',_schedulePreferencesAutosave,{once:false});
if(showCliCb){showCliCb.addEventListener('change',function(){showKanbanCb.disabled=!showCliCb.checked;},{once:false});}
}
const showPreviousMessagingCb=$('settingsShowPreviousMessagingSessions');
if(showPreviousMessagingCb){showPreviousMessagingCb.checked=!!settings.show_previous_messaging_sessions;showPreviousMessagingCb.addEventListener('change',_schedulePreferencesAutosave,{once:false});}
const syncCb=$('settingsSyncInsights');
@@ -12557,6 +12566,7 @@ async function saveSettings(andClose){
const showClaudeCodeSessions=!!($('settingsShowClaudeCodeSessions')||{}).checked;
const showCronSessions=!!($('settingsShowCronSessions')||{}).checked;
const showWebhookSessions=!!($('settingsShowWebhookSessions')||{}).checked;
const showKanbanSessions=!!($('settingsShowKanbanSessions')||{}).checked;
const showPreviousMessagingSessions=!!($('settingsShowPreviousMessagingSessions')||{}).checked;
const pinnedSessionsLimit=parseInt(($('settingsPinnedSessionsLimit')||{}).value,10)||3;
const pw=($('settingsPassword')||{}).value;
@@ -12613,6 +12623,7 @@ async function saveSettings(andClose){
// mirror the autosave path so the explicit Save Settings button persists them too. (#3514)
body.show_cron_sessions=showCliSessions&&showCronSessions;
body.show_webhook_sessions=showCliSessions&&showWebhookSessions;
body.show_kanban_sessions=showCliSessions&&showKanbanSessions;
body.show_previous_messaging_sessions=showPreviousMessagingSessions;
body.pinned_sessions_limit=pinnedSessionsLimit;
body.sync_to_insights=!!($('settingsSyncInsights')||{}).checked;
@@ -31,6 +31,29 @@ def test_webhook_visible_when_show_webhook_true():
) is False
def test_kanban_hidden_by_default():
assert _hide_from_default_sidebar({'source_tag': 'kanban', 'session_id': 'kanban_worker_1'}) is True
def test_kanban_visible_when_show_kanban_true():
assert _hide_from_default_sidebar(
{'source_tag': 'kanban', 'session_id': 'kanban_worker_1'},
show_kanban=True,
) is False
def test_kanban_hidden_with_explicit_false():
assert _hide_from_default_sidebar({'source_tag': 'kanban', 'session_id': 'kanban_worker_1'}, show_kanban=False) is True
def test_kanban_does_not_leak_when_other_toggles_enabled():
assert _hide_from_default_sidebar(
{'source_tag': 'kanban', 'session_id': 'kanban_worker_1'},
show_cron=True,
show_webhook=True,
) is True
def test_pre_compression_always_hidden_regardless_of_background_toggles():
assert _hide_from_default_sidebar({'pre_compression_snapshot': True}, show_cron=True, show_webhook=True) is True
@@ -55,6 +78,13 @@ def test_show_webhook_sessions_in_defaults():
)
def test_show_kanban_sessions_in_defaults():
src = _read("api/config.py")
assert '"show_kanban_sessions": False' in src, (
'"show_kanban_sessions": False must appear in _SETTINGS_DEFAULTS'
)
def test_show_cron_sessions_in_bool_keys():
src = _read("api/config.py")
assert '"show_cron_sessions"' in src, (
@@ -76,6 +106,16 @@ def test_show_webhook_sessions_in_bool_keys():
)
def test_show_kanban_sessions_in_bool_keys():
src = _read("api/config.py")
assert '"show_kanban_sessions"' in src, (
'"show_kanban_sessions" must appear in _SETTINGS_BOOL_KEYS'
)
assert src.count('"show_kanban_sessions"') >= 2, (
'"show_kanban_sessions" must appear in both _SETTINGS_DEFAULTS and _SETTINGS_BOOL_KEYS'
)
# --- api/routes.py string-scan ---
def test_show_cron_sessions_kwarg_passthrough():
@@ -92,6 +132,25 @@ def test_show_webhook_sessions_kwarg_passthrough():
)
def test_show_kanban_sessions_kwarg_passthrough():
src = _read("api/routes.py")
assert "show_kanban_sessions=show_kanban_sessions" in src, (
"show_kanban_sessions kwarg must be forwarded at the _dedupe_cli_sidebar_sessions_for_api call site"
)
assert "show_kanban=show_kanban_sessions" in src, (
"show_kanban kwarg must be forwarded to _hide_background in _dedupe_cli_sidebar_sessions_for_api"
)
def test_show_kanban_sessions_invalidates_session_cache_on_settings_save():
src = _read("api/routes.py")
invalidation_block = src.split("Settings that change which sessions appear in the sidebar", 1)[1]
invalidation_block = invalidation_block.split("auth_enabled_after", 1)[0]
assert '"show_kanban_sessions"' in invalidation_block, (
"settings POST must explicitly invalidate /api/sessions cache when show_kanban_sessions changes"
)
def test_show_webhook_sessions_invalidates_session_cache_on_settings_save():
src = _read("api/routes.py")
invalidation_block = src.split("Settings that change which sessions appear in the sidebar", 1)[1]
@@ -117,6 +176,13 @@ def test_settings_show_webhook_sessions_in_html():
)
def test_settings_show_kanban_sessions_in_html():
src = _read("static/index.html")
assert "settingsShowKanbanSessions" in src, (
"settingsShowKanbanSessions checkbox must appear in static/index.html"
)
# --- static/panels.js string-scans ---
def test_panels_save_wiring():
@@ -136,6 +202,12 @@ def test_panels_save_wiring():
assert "body.show_webhook_sessions=showCliSessions&&showWebhookSessions" in src, (
"explicit saveSettings() must gate show_webhook_sessions on showCliSessions in static/panels.js"
)
assert "payload.show_kanban_sessions=!!(showCliCb&&showCliCb.checked&&showKanbanCb.checked)" in src, (
"autosave wiring must gate show_kanban_sessions on settingsShowCliSessions in static/panels.js"
)
assert "body.show_kanban_sessions=showCliSessions&&showKanbanSessions" in src, (
"explicit saveSettings() must gate show_kanban_sessions on showCliSessions in static/panels.js"
)
def test_panels_load_wiring():
@@ -146,3 +218,55 @@ def test_panels_load_wiring():
assert "show_webhook_sessions" in src, (
"load wiring for show_webhook_sessions must appear in static/panels.js"
)
assert "show_kanban_sessions" in src, (
"load wiring for show_kanban_sessions must appear in static/panels.js"
)
# --- #6780 gate-fix regressions: cron/webhook parity for kanban ---
def test_kanban_source_filter_overrides_default_hide():
"""An explicit kanban source_filter is a deliberate request to view kanban
rows, so _dedupe_cli_sidebar_sessions_for_api must reveal them even though
show_kanban_sessions is False (mirrors cron/webhook source-filter behavior)."""
from api.routes import _dedupe_cli_sidebar_sessions_for_api
kanban_row = {"session_id": "kb1", "source": "kanban", "message_count": 3}
# Default (no filter): kanban is hidden.
hidden = _dedupe_cli_sidebar_sessions_for_api(
[dict(kanban_row)], set(), show_kanban_sessions=False, source_filter=None
)
assert not any(s["session_id"] == "kb1" for s in hidden), (
"kanban row must be hidden by default with no source_filter"
)
# Explicit kanban filter: revealed despite show_kanban_sessions=False.
revealed = _dedupe_cli_sidebar_sessions_for_api(
[dict(kanban_row)], set(), show_kanban_sessions=False, source_filter="kanban"
)
assert any(s["session_id"] == "kb1" for s in revealed), (
"explicit kanban source_filter must override the default hide"
)
def test_kanban_filtered_view_capped_at_chip_limit():
"""A filtered kanban-only view (source_filter=='kanban') is bounded by a
dedicated KANBAN_PROJECT_CHIP_LIMIT, mirroring cron/webhook. (Kanban is NOT
added to the general exclude_sources — the original PR intentionally lets
kanban load on the source_filter=None path so the toggle-on case works; the
hide is applied by _hide_from_default_sidebar only when the toggle is off.)"""
src = _read("api/models.py")
assert "KANBAN_PROJECT_CHIP_LIMIT if source_filter == 'kanban'" in src, (
"a bounded kanban-only project-chip limit must exist for the filtered view"
)
assert '("cron", "webhook") if source_filter is None' in src, (
"kanban must NOT be excluded from the general query (would break toggle-on)"
)
def test_kanban_source_filter_passed_to_dedupe():
src = _read("api/routes.py")
assert "source_filter=source_filter," in src, (
"source_filter must be forwarded to _dedupe_cli_sidebar_sessions_for_api "
"so an explicit kanban filter can override the hide"
)