feat: add MCP session visibility toggle and rebuild release
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
const CCWEB_PROMPT_VIEW_MODE_STORAGE_KEY = 'cc-web-ccweb-prompt-view-mode';
|
||||
const PROJECT_COLLAPSE_STORAGE_KEY = 'cc-web-collapsed-projects';
|
||||
const SIDEBAR_COLLAPSE_STORAGE_KEY = 'cc-web-sidebar-collapsed';
|
||||
const MCP_SESSION_VISIBILITY_STORAGE_KEY = 'cc-web-mcp-session-visibility';
|
||||
const SIDEBAR_DRAWER_MEDIA_QUERY = '(max-width: 768px)';
|
||||
const SIDEBAR_DESKTOP_COLLAPSE_MEDIA_QUERY = '(width > 768px)';
|
||||
const SIDEBAR_HOVER_PREVIEW_MEDIA_QUERY = '(width > 768px) and (hover: hover) and (pointer: fine)';
|
||||
@@ -272,6 +273,7 @@
|
||||
let isReloadingMcp = false;
|
||||
const mcpStartupToastKeys = new Map();
|
||||
let sessionSearchQuery = '';
|
||||
let showMcpSessions = readMcpSessionVisibilityPreference();
|
||||
const advancedSessionSearchState = {
|
||||
open: false,
|
||||
query: '',
|
||||
@@ -365,6 +367,7 @@
|
||||
const importSessionBtn = $('#import-session-btn');
|
||||
const sessionSearchInput = $('#session-search-input');
|
||||
const sessionSearchClear = $('#session-search-clear');
|
||||
const mcpSessionVisibilityToggle = $('#mcp-session-visibility-toggle');
|
||||
const advancedSearchOpen = $('#advanced-search-open');
|
||||
const advancedSearchPanel = $('#advanced-search-panel');
|
||||
const advancedSearchClose = $('#advanced-search-close');
|
||||
@@ -4521,6 +4524,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
function readMcpSessionVisibilityPreference() {
|
||||
try {
|
||||
return localStorage.getItem(MCP_SESSION_VISIBILITY_STORAGE_KEY) !== 'false';
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function persistMcpSessionVisibilityPreference(visible) {
|
||||
try {
|
||||
localStorage.setItem(MCP_SESSION_VISIBILITY_STORAGE_KEY, visible ? 'true' : 'false');
|
||||
} catch {
|
||||
// 存储不可用时仍保留当前页面内的筛选状态。
|
||||
}
|
||||
}
|
||||
|
||||
function sessionPassesMcpVisibilityFilter(session, normalizedSearchQuery = '') {
|
||||
if (normalizedSearchQuery) return true;
|
||||
if (showMcpSessions) return true;
|
||||
const isMcpCreated = String(session?.createdFromKind || '').toLowerCase() === 'mcp';
|
||||
if (!isMcpCreated) return true;
|
||||
return session.id === currentSessionId || !!session.isRunning;
|
||||
}
|
||||
|
||||
function syncMcpSessionVisibilityToggle() {
|
||||
if (!mcpSessionVisibilityToggle) return;
|
||||
const isHidingMcpSessions = !showMcpSessions;
|
||||
const actionLabel = isHidingMcpSessions ? '显示 MCP 会话' : '隐藏 MCP 会话';
|
||||
mcpSessionVisibilityToggle.setAttribute('aria-pressed', String(isHidingMcpSessions));
|
||||
mcpSessionVisibilityToggle.title = actionLabel;
|
||||
mcpSessionVisibilityToggle.setAttribute('aria-label', actionLabel);
|
||||
}
|
||||
|
||||
function getSessionSearchText(session) {
|
||||
const cwd = getSessionEffectiveCwd(session);
|
||||
return [
|
||||
@@ -10856,6 +10892,7 @@
|
||||
return JSON.stringify({
|
||||
agent: currentAgent,
|
||||
currentSessionId,
|
||||
showMcpSessions,
|
||||
search: model.normalizedSearchQuery,
|
||||
allEmpty: model.allVisibleSessions.length === 0,
|
||||
visibleEmpty: model.visibleSessions.length === 0,
|
||||
@@ -10890,12 +10927,16 @@
|
||||
|
||||
function renderSessionList() {
|
||||
syncSessionSearchUi();
|
||||
syncMcpSessionVisibilityToggle();
|
||||
const allVisibleSessions = getVisibleSessions();
|
||||
const normalizedSearchQuery = normalizeSessionSearchQuery(sessionSearchQuery);
|
||||
const isSearchingSessions = !!normalizedSearchQuery;
|
||||
const mcpVisibilityFilteredSessions = allVisibleSessions.filter((session) => (
|
||||
sessionPassesMcpVisibilityFilter(session, normalizedSearchQuery)
|
||||
));
|
||||
const visibleSessions = isSearchingSessions
|
||||
? allVisibleSessions.filter((session) => sessionMatchesSearch(session, normalizedSearchQuery))
|
||||
: allVisibleSessions;
|
||||
? mcpVisibilityFilteredSessions.filter((session) => sessionMatchesSearch(session, normalizedSearchQuery))
|
||||
: mcpVisibilityFilteredSessions;
|
||||
const { pinnedSessions, regularSessions } = splitPinnedSessions(visibleSessions);
|
||||
const { groups: projectGroups, ungroupedSessions } = groupSessionsByProject(regularSessions);
|
||||
const renderGroups = projectGroups.map((group, groupIndex) => {
|
||||
@@ -10951,7 +10992,7 @@
|
||||
if (visibleSessions.length === 0) {
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'session-list-empty';
|
||||
empty.textContent = '没有匹配的会话或项目。';
|
||||
empty.textContent = isSearchingSessions ? '没有匹配的会话或项目。' : 'MCP 会话已隐藏。';
|
||||
sessionList.appendChild(empty);
|
||||
lastSessionListStructureSignature = structureSignature;
|
||||
return;
|
||||
@@ -11821,6 +11862,14 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (mcpSessionVisibilityToggle) {
|
||||
mcpSessionVisibilityToggle.addEventListener('click', () => {
|
||||
showMcpSessions = !showMcpSessions;
|
||||
persistMcpSessionVisibilityPreference(showMcpSessions);
|
||||
renderSessionList();
|
||||
});
|
||||
}
|
||||
|
||||
if (advancedSearchOpen && advancedSearchPanel) {
|
||||
advancedSearchOpen.addEventListener('click', openAdvancedSessionSearch);
|
||||
advancedSearchClose?.addEventListener('click', () => closeAdvancedSessionSearch());
|
||||
|
||||
@@ -63,6 +63,13 @@
|
||||
<input id="session-search-input" class="session-search-input" type="search" placeholder="检索会话 / 项目" autocomplete="off" aria-label="检索会话或项目">
|
||||
<button id="session-search-clear" class="session-search-clear" type="button" title="清空检索" aria-label="清空检索" hidden>×</button>
|
||||
</div>
|
||||
<button id="mcp-session-visibility-toggle" class="mcp-session-visibility-toggle icon-only" type="button" title="隐藏 MCP 会话" aria-label="隐藏 MCP 会话" aria-pressed="false">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"></path>
|
||||
<circle cx="12" cy="12" r="2.5"></circle>
|
||||
<path class="mcp-session-visibility-slash" d="m4 4 16 16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button id="advanced-search-open" class="advanced-search-open" type="button" title="高级会话检索" aria-label="打开高级会话检索" aria-controls="advanced-search-panel" aria-expanded="false">⌘</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1252,11 +1252,13 @@ body.session-loading-active {
|
||||
color: var(--text-primary);
|
||||
outline: none;
|
||||
}
|
||||
.advanced-search-open {
|
||||
.advanced-search-open,
|
||||
.mcp-session-visibility-toggle {
|
||||
appearance: none;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
flex: 0 0 34px;
|
||||
flex-basis: 34px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -1277,6 +1279,29 @@ body.session-loading-active {
|
||||
transform 0.16s ease,
|
||||
box-shadow 0.16s ease;
|
||||
}
|
||||
.mcp-session-visibility-toggle svg {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.8;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.mcp-session-visibility-slash {
|
||||
opacity: 0;
|
||||
transition: opacity 0.16s ease;
|
||||
}
|
||||
.mcp-session-visibility-toggle[aria-pressed='true'] {
|
||||
background: var(--accent-light);
|
||||
border-color: rgba(192, 85, 58, 0.34);
|
||||
color: var(--accent);
|
||||
}
|
||||
.mcp-session-visibility-toggle[aria-pressed='true'] .mcp-session-visibility-slash {
|
||||
opacity: 1;
|
||||
}
|
||||
.mcp-session-visibility-toggle:hover,
|
||||
.mcp-session-visibility-toggle:focus-visible,
|
||||
.advanced-search-open:hover,
|
||||
.advanced-search-open:focus-visible {
|
||||
background: var(--accent-light);
|
||||
@@ -1285,6 +1310,7 @@ body.session-loading-active {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(192, 85, 58, 0.1);
|
||||
}
|
||||
.mcp-session-visibility-toggle:active,
|
||||
.advanced-search-open:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
@@ -2137,7 +2163,7 @@ body.session-loading-active {
|
||||
html[data-theme='cinder'],
|
||||
html[data-theme='gilded'],
|
||||
html[data-theme='wasteland']
|
||||
) .advanced-search-open {
|
||||
) :is(.advanced-search-open, .mcp-session-visibility-toggle) {
|
||||
background: var(--dark-panel-soft);
|
||||
border-color: var(--theme-card-border);
|
||||
color: var(--text-secondary);
|
||||
@@ -2149,14 +2175,14 @@ body.session-loading-active {
|
||||
html[data-theme='cinder'],
|
||||
html[data-theme='gilded'],
|
||||
html[data-theme='wasteland']
|
||||
) .advanced-search-open:hover,
|
||||
) :is(.advanced-search-open, .mcp-session-visibility-toggle):hover,
|
||||
:is(
|
||||
html[data-theme='carbon'],
|
||||
html[data-theme='nocturne'],
|
||||
html[data-theme='cinder'],
|
||||
html[data-theme='gilded'],
|
||||
html[data-theme='wasteland']
|
||||
) .advanced-search-open:focus-visible {
|
||||
) :is(.advanced-search-open, .mcp-session-visibility-toggle):focus-visible {
|
||||
background: var(--accent-light);
|
||||
border-color: var(--theme-card-hover-border);
|
||||
color: var(--accent);
|
||||
@@ -2192,6 +2218,15 @@ html[data-theme='wasteland'] .advanced-search-open {
|
||||
clip-path: var(--wasteland-cut);
|
||||
}
|
||||
|
||||
html[data-theme='wasteland'] .mcp-session-visibility-toggle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
flex-basis: 36px;
|
||||
border-color: var(--wasteland-line);
|
||||
border-radius: 0;
|
||||
clip-path: var(--wasteland-cut);
|
||||
}
|
||||
|
||||
html[data-theme='wasteland'] .advanced-search-panel {
|
||||
--advanced-search-bg: #151715;
|
||||
--advanced-search-line: var(--wasteland-line);
|
||||
@@ -2309,6 +2344,7 @@ html[data-theme='wasteland'] .advanced-search-panel {
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.advanced-search-open,
|
||||
.mcp-session-visibility-toggle,
|
||||
.advanced-search-close,
|
||||
.advanced-search-submit,
|
||||
.advanced-search-pill {
|
||||
@@ -9502,6 +9538,12 @@ html[data-theme='wasteland'] .session-search-row .advanced-search-open {
|
||||
flex-basis: 36px;
|
||||
}
|
||||
|
||||
html[data-theme='wasteland'] .session-search-row .mcp-session-visibility-toggle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
flex-basis: 36px;
|
||||
}
|
||||
|
||||
html[data-theme='wasteland'] .session-search::after {
|
||||
inset: 0;
|
||||
background-image: url('assets/themes/wasteland/frames/search.png');
|
||||
|
||||
Reference in New Issue
Block a user