diff --git a/frontend/src/App.css b/frontend/src/App.css index 37abf2e0..cf2fbf62 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1174,8 +1174,9 @@ body[data-ui-version] .gonavi-settings-center-modal .gonavi-settings-center-entr height: auto !important; min-height: 58px; padding: 8px 6px !important; - border-inline: 0 !important; - border-radius: 0 !important; + border: none !important; + border-radius: 4px !important; + font-size: var(--gn-settings-font-body) !important; } body[data-ui-version] .gonavi-settings-center-modal .gonavi-ai-provider-add.ant-btn { @@ -1322,25 +1323,36 @@ body[data-theme='dark'] .gonavi-language-option.is-selected { } .gonavi-ai-mcp-tabs { - display: flex; - align-items: stretch; - gap: 22px; + display: inline-flex; + align-items: center; + align-self: flex-start; + gap: 4px; min-height: 44px; + padding: 4px; + border-radius: 7px; + background: rgba(15, 23, 42, 0.05); } .gonavi-ai-mcp-tab { display: inline-flex; align-items: center; + justify-content: center; gap: 6px; - margin-bottom: -1px; - padding: 0 2px; - border: 0; - border-bottom: 2px solid transparent; + min-height: 36px; + padding: 0 14px; + border: 1px solid transparent; + border-radius: 5px; background: transparent; font-size: 13px; font-weight: 700; cursor: pointer; - transition: color 160ms ease, border-color 160ms ease; + transition: color 160ms ease, border-color 160ms ease, background 160ms ease, box-shadow 160ms ease; +} + +.gonavi-ai-mcp-tab.is-active { + border-color: var(--gn-mcp-accent, #16a34a); + background: var(--gn-mcp-accent-bg, rgba(22, 163, 74, 0.12)); + box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08); } .gonavi-ai-mcp-route-arrow { @@ -1356,27 +1368,50 @@ body[data-theme='dark'] .gonavi-language-option.is-selected { .gonavi-ai-mcp-tab:hover:not(.is-active) { color: rgba(15, 23, 42, 0.88) !important; + background: rgba(255, 255, 255, 0.64); } body[data-theme='dark'] .gonavi-ai-mcp-tab:hover:not(.is-active) { color: rgba(248, 250, 252, 0.9) !important; + background: rgba(255, 255, 255, 0.06); +} + +body[data-theme='dark'] .gonavi-ai-mcp-tabs { + background: rgba(255, 255, 255, 0.06); +} + +body[data-theme='dark'] .gonavi-ai-mcp-tab.is-active { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.24); +} + +.gonavi-ai-mcp-panel { + flex-direction: column; + gap: 12px; } .gonavi-ai-mcp-tab:focus-visible, -.gonavi-ai-mcp-disclosure > summary:focus-visible { +.gonavi-ai-mcp-disclosure > summary:focus-visible, +.gonavi-ai-mcp-client-option:focus-visible { outline: 2px solid rgba(22, 163, 74, 0.55); outline-offset: 2px; } +.gonavi-ai-mcp-disclosure { + border-radius: 6px; +} + .gonavi-ai-mcp-disclosure > summary { display: flex; align-items: center; gap: 10px; - min-height: 42px; - padding-right: 2px; + min-height: 52px; + padding: 6px 8px 6px 12px; + border-radius: 6px; + background: rgba(15, 23, 42, 0.038); list-style: none; cursor: pointer; user-select: none; + transition: background 160ms ease; } .gonavi-ai-mcp-disclosure > summary::-webkit-details-marker { @@ -1385,24 +1420,233 @@ body[data-theme='dark'] .gonavi-ai-mcp-tab:hover:not(.is-active) { .gonavi-ai-mcp-disclosure > summary::after { content: '›'; + display: grid; + place-items: center; + width: 30px; + height: 30px; margin-left: auto; + border-radius: 5px; + background: rgba(15, 23, 42, 0.07); color: rgba(100, 116, 139, 0.78); - font-size: 18px; + font-size: 20px; + font-weight: 700; line-height: 1; + flex: 0 0 30px; transform: rotate(0deg); - transition: transform 160ms ease; + transition: color 160ms ease, background 160ms ease, transform 160ms ease; } .gonavi-ai-mcp-disclosure[open] > summary::after { + background: var(--gn-mcp-accent-bg, rgba(22, 163, 74, 0.12)); + color: var(--gn-mcp-accent, #16a34a); transform: rotate(90deg); } .gonavi-ai-mcp-disclosure > summary:hover { - background: rgba(15, 23, 42, 0.025); + background: rgba(15, 23, 42, 0.065); +} + +.gonavi-ai-mcp-disclosure > summary:hover::after { + background: rgba(15, 23, 42, 0.11); } body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary:hover { - background: rgba(255, 255, 255, 0.035); + background: rgba(255, 255, 255, 0.075); +} + +body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary { + background: rgba(255, 255, 255, 0.045); +} + +body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary::after { + background: rgba(255, 255, 255, 0.075); + color: rgba(203, 213, 225, 0.86); +} + +body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary:hover::after { + background: rgba(255, 255, 255, 0.12); +} + +body[data-theme='dark'] .gonavi-ai-mcp-disclosure[open] > summary::after { + background: var(--gn-mcp-accent-bg, rgba(34, 197, 94, 0.14)); + color: var(--gn-mcp-accent, #86efac); +} + +.gonavi-ai-tool-view-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 4px; + padding: 4px; + border-radius: 7px; + background: rgba(15, 23, 42, 0.05); +} + +.gonavi-ai-tool-view-tab { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 8px; + min-width: 0; + min-height: 44px; + padding: 6px 12px; + border: 1px solid transparent; + border-radius: 5px; + background: transparent; + font-family: inherit; + font-size: var(--gn-settings-font-secondary, 13px); + font-weight: 700; + letter-spacing: 0; + cursor: pointer; + transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease; +} + +.gonavi-ai-tool-view-tab:hover:not(.is-active) { + background: rgba(255, 255, 255, 0.68); +} + +.gonavi-ai-tool-view-tab.is-active { + border-color: var(--gn-ai-disclosure-accent, #16a34a); + background: var(--gn-ai-disclosure-accent-bg, rgba(22, 163, 74, 0.12)); + box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08); +} + +.gonavi-ai-tool-view-tab:focus-visible { + outline: 2px solid var(--gn-ai-disclosure-accent, rgba(22, 163, 74, 0.55)); + outline-offset: 2px; +} + +.gonavi-ai-tool-view-tab-icon { + font-size: 14px; +} + +.gonavi-ai-tool-view-tab-label { + min-width: 0; + line-height: 1.25; + overflow-wrap: anywhere; +} + +.gonavi-ai-tool-view-count { + min-width: 42px; + padding: 0 5px; + border-radius: 4px; + background: rgba(15, 23, 42, 0.065); + color: inherit; + font-family: var(--gn-font-mono); + font-size: 11px; + font-variant-numeric: tabular-nums; + font-weight: 650; + line-height: 20px; + text-align: center; +} + +.gonavi-ai-tool-view-tab.is-active .gonavi-ai-tool-view-count { + background: rgba(22, 163, 74, 0.12); +} + +.gonavi-ai-tool-view-empty { + padding: 20px 10px; + border-radius: 4px; + font-size: var(--gn-settings-font-secondary, 13px); + line-height: 1.7; +} + +body[data-theme='dark'] .gonavi-ai-tool-view-tabs { + background: rgba(255, 255, 255, 0.06); +} + +body[data-theme='dark'] .gonavi-ai-tool-view-tab:hover:not(.is-active) { + background: rgba(255, 255, 255, 0.06); +} + +body[data-theme='dark'] .gonavi-ai-tool-view-tab.is-active { + background: var(--gn-ai-disclosure-accent-bg, rgba(34, 197, 94, 0.14)); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.24); +} + +body[data-theme='dark'] .gonavi-ai-tool-view-count { + background: rgba(255, 255, 255, 0.075); +} + +.gonavi-ai-settings-disclosure > summary { + display: flex; + align-items: center; + gap: 10px; + min-height: 48px; + padding: 5px 6px 5px 10px; + border-radius: 5px; + background: transparent; + list-style: none; + cursor: pointer; + user-select: none; + transition: background 160ms ease; +} + +.gonavi-ai-settings-disclosure > summary::-webkit-details-marker { + display: none; +} + +.gonavi-ai-settings-disclosure > summary::marker { + content: ''; +} + +.gonavi-ai-settings-disclosure-content { + min-width: 0; + flex: 1 1 auto; +} + +.gonavi-ai-settings-disclosure-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 5px; + background: rgba(15, 23, 42, 0.065); + color: rgba(100, 116, 139, 0.82); + font-size: 12px; + flex: 0 0 28px; + transform: rotate(0deg); + transition: color 160ms ease, background 160ms ease, transform 160ms ease; +} + +.gonavi-ai-settings-disclosure > summary:hover { + background: rgba(15, 23, 42, 0.04); +} + +.gonavi-ai-settings-disclosure[open] > summary { + background: var(--gn-ai-disclosure-accent-bg, rgba(22, 163, 74, 0.1)); +} + +.gonavi-ai-settings-disclosure[open] > summary .gonavi-ai-settings-disclosure-icon { + background: var(--gn-ai-disclosure-accent-bg, rgba(22, 163, 74, 0.12)); + color: var(--gn-ai-disclosure-accent, #16a34a); + transform: rotate(90deg); +} + +.gonavi-ai-settings-disclosure > summary:focus-visible { + outline: 2px solid var(--gn-ai-disclosure-accent, rgba(22, 163, 74, 0.55)); + outline-offset: 2px; +} + +body[data-theme='dark'] .gonavi-ai-settings-disclosure > summary:hover { + background: rgba(255, 255, 255, 0.05); +} + +body[data-theme='dark'] .gonavi-ai-settings-disclosure-icon { + background: rgba(255, 255, 255, 0.075); + color: rgba(203, 213, 225, 0.86); +} + +body[data-theme='dark'] .gonavi-ai-settings-disclosure[open] > summary { + background: var(--gn-ai-disclosure-accent-bg, rgba(34, 197, 94, 0.12)); +} + +@media (prefers-reduced-motion: reduce) { + .gonavi-ai-tool-view-tab, + .gonavi-ai-settings-disclosure > summary, + .gonavi-ai-settings-disclosure-icon { + transition: none; + } } .gonavi-ai-mcp-summary-note, @@ -1416,9 +1660,74 @@ body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary:hover { .gonavi-ai-mcp-summary-note { flex: 1; + padding-right: 4px; font-size: var(--gn-font-size-sm, 12px); } +.gonavi-ai-mcp-client-options { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 8px; +} + +.gonavi-ai-mcp-client-option { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + width: 100%; + min-height: 58px; + padding: 11px 12px; + border: 1px solid transparent; + border-radius: 6px; + background: rgba(15, 23, 42, 0.035); + cursor: pointer; + text-align: left; + transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease; +} + +.gonavi-ai-mcp-client-option:hover:not(.is-active) { + background: rgba(15, 23, 42, 0.065); +} + +.gonavi-ai-mcp-client-option.is-active { + border-color: var(--gn-mcp-accent, #16a34a); + background: var(--gn-mcp-accent-bg, rgba(22, 163, 74, 0.12)); + box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08); +} + +.gonavi-ai-mcp-client-option-state { + display: inline-flex; + align-items: center; + gap: 5px; + flex: 0 0 auto; +} + +.gonavi-ai-mcp-client-check { + font-size: 14px; + flex: 0 0 auto; +} + +.gonavi-ai-mcp-client-status-panel { + padding: 14px; + border-radius: 6px; + background: rgba(15, 23, 42, 0.03); +} + +body[data-theme='dark'] .gonavi-ai-mcp-client-option, +body[data-theme='dark'] .gonavi-ai-mcp-client-status-panel { + background: rgba(255, 255, 255, 0.04); +} + +body[data-theme='dark'] .gonavi-ai-mcp-client-option:hover:not(.is-active) { + background: rgba(255, 255, 255, 0.075); +} + +body[data-theme='dark'] .gonavi-ai-mcp-client-option.is-active { + background: var(--gn-mcp-accent-bg, rgba(34, 197, 94, 0.14)); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.24); +} + .gonavi-ai-mcp-server-row > summary { min-height: 50px; padding-left: 13px; @@ -1438,7 +1747,23 @@ body[data-theme='dark'] .gonavi-ai-mcp-disclosure > summary:hover { } .gonavi-ai-mcp-tabs { - gap: 16px; + width: 100%; + } + + .gonavi-ai-mcp-tab { + min-width: 0; + padding: 0 9px; + flex: 1 1 0; + } + + .gonavi-ai-mcp-client-options { + grid-template-columns: 1fr; + } +} + +@media (min-width: 761px) and (max-width: 1100px) { + .gonavi-ai-mcp-client-options { + grid-template-columns: repeat(2, minmax(0, 1fr)); } } diff --git a/frontend/src/App.settings-center.test.ts b/frontend/src/App.settings-center.test.ts index 350dd8af..f9203748 100644 --- a/frontend/src/App.settings-center.test.ts +++ b/frontend/src/App.settings-center.test.ts @@ -59,6 +59,19 @@ describe('settings center layout', () => { expect(appSource).not.toContain("setIsLanguageModalOpen(true)"); }); + it('removes redundant framing lines from settings detail pages', () => { + const detailPanelStyleStart = appSource.indexOf('const activeSettingsCenterDetailPanelStyle'); + const detailPanelStyleEnd = appSource.indexOf('const settingsCenterDetailBodyStyle', detailPanelStyleStart); + const detailPanelStyleSource = appSource.slice(detailPanelStyleStart, detailPanelStyleEnd); + const detailShellStart = appSource.indexOf('style={activeSettingsCenterDetailPanelStyle}'); + const detailShellEnd = appSource.indexOf('className="gonavi-settings-center-entry"', detailShellStart); + const detailShellSource = appSource.slice(detailShellStart, detailShellEnd); + + expect(detailPanelStyleSource).toContain("borderBottom: 'none'"); + expect(detailShellSource).toContain('
'); + expect(detailShellSource).not.toContain('borderTop: `1px solid ${overlayTheme.divider}`'); + }); + it('adds persistent sidebar object visibility controls to preferences', () => { expect(appSource).toContain("key: 'sidebar-objects'"); expect(appSource).toContain("title: t('app.settings.sidebar_objects.title')"); @@ -126,6 +139,9 @@ describe('settings center layout', () => { expect(appSource).toContain("t('app.data_root.log_directory.environment_hint')"); expect(appSource).toContain("t('app.data_root.log_directory.pending_restart')"); expect(appSource).toContain("t('app.data_root.log_directory.restart_hint')"); + expect(logDirectoryRendererSource).not.toContain( + "
{t('app.data_root.log_directory.title')}
", + ); expect(logDirectoryRendererSource).not.toContain("t('app.data_root.log_directory.target_directory')"); expect(logDirectoryRendererSource.match(/disabled={!editable \|\| directorySettingsApplying}/g)).toHaveLength(3); expect(embeddedDataRootSource.match(/disabled={directorySettingsApplying}/g)).toHaveLength(4); diff --git a/frontend/src/App.tool-center.test.ts b/frontend/src/App.tool-center.test.ts index 4e5e9584..119b209d 100644 --- a/frontend/src/App.tool-center.test.ts +++ b/frontend/src/App.tool-center.test.ts @@ -104,6 +104,36 @@ describe('settings center tool entries', () => { expect(appSource).not.toContain('const [isToolsModalOpen'); }); + it('uses whitespace instead of decorative rules for settings navigation and panels', () => { + const utilityPanelStyleSource = appUtilityStylesSource.slice( + appUtilityStylesSource.indexOf('const utilityPanelStyle'), + appUtilityStylesSource.indexOf('const toolCenterModalContentStyle'), + ); + const navScrollStyleSource = appUtilityStylesSource.slice( + appUtilityStylesSource.indexOf('const toolCenterNavScrollStyle'), + appUtilityStylesSource.indexOf('const toolCenterContentPanelStyle'), + ); + const scrollableListStyleSource = appUtilityStylesSource.slice( + appUtilityStylesSource.indexOf('const toolCenterScrollableListStyle'), + appUtilityStylesSource.indexOf('const utilityMutedTextStyle'), + ); + const groupTabsStart = appSource.indexOf('combinedSettingsCenterGroups.map'); + const groupTabSource = appSource.slice(groupTabsStart, appSource.indexOf('', groupTabsStart)); + const entryListStart = appSource.indexOf('activeSettingsCenterGroup.items.map'); + const entryListSource = appSource.slice(entryListStart, appSource.indexOf('', entryListStart)); + + expect(utilityPanelStyleSource).toContain("border: 'none'"); + expect(utilityPanelStyleSource).not.toContain('borderBottom'); + expect(navScrollStyleSource).toContain('gap: 2'); + expect(navScrollStyleSource).not.toContain('borderTop'); + expect(scrollableListStyleSource).toContain('gap: 2'); + expect(groupTabSource).not.toContain('borderBottom'); + expect(entryListSource).not.toContain('borderTop'); + expect(entryListSource).not.toContain('borderBottom'); + expect(appCss).toMatch(/\.gonavi-settings-center-entry\.ant-btn\s*\{[^}]*border:\s*none !important;/s); + expect(appCss).toMatch(/\.gonavi-settings-center-entry\.ant-btn\s*\{[^}]*border-radius:\s*4px !important;/s); + }); + it('keeps the unified settings modal height fixed across group switches and scrolls the list area internally', () => { expect(appUtilityStylesSource).toContain('const toolCenterModalContentStyle = useMemo(() => ({'); expect(appUtilityStylesSource).toContain("height: 'min(820px, calc(100vh - 64px))'"); @@ -120,8 +150,6 @@ describe('settings center tool entries', () => { expect(appSource).toContain('style={isActiveToolCenterPane ? toolCenterDetailBodyStyle : settingsCenterDetailBodyStyle}'); expect(appSource).toContain('style={toolCenterScrollableListStyle}'); expect(appUtilityStylesSource).toContain("overflowY: 'auto'"); - expect(appSource).toContain("borderTop: index === 0 ? `1px solid ${overlayTheme.divider}` : 'none'"); - expect(appSource).toContain("borderBottom: `1px solid ${overlayTheme.divider}`"); }); it('keeps browser-compatible connection transfer and mounted data-root entries available in the web runtime', () => { @@ -396,7 +424,7 @@ describe('settings center tool entries', () => { it('executes every global shortcut action exposed in the shortcut manager', () => { const expectedHandlers = new Map([ ['runQuery', 'gonavi:run-active-query'], - ['focusSidebarSearch', 'gonavi:focus-sidebar-search'], + ['focusSidebarSearch', 'handleFocusSidebarSearch();'], ['newQueryTab', 'handleNewQuery();'], ['switchToNextTab', 'switchActiveTabByOffset(1);'], ['switchToPreviousTab', 'switchActiveTabByOffset(-1);'], @@ -415,7 +443,7 @@ describe('settings center tool entries', () => { expect(appSource).toContain('const switchActiveTabByOffset = useCallback((offset: 1 | -1) => {'); expect(appSource).toContain('const nextIndex = (baseIndex + offset + tabs.length) % tabs.length;'); expect(appSource).toContain('setActiveTab(tabs[nextIndex].id);'); - expect(appSource).toContain('handleCreateConnection, handleManualResetWindowZoom'); + expect(appSource).toContain('handleCreateConnection, handleFocusSidebarSearch, handleManualResetWindowZoom'); expect(appSource).toContain('switchActiveTabByOffset, themeMode'); }); @@ -619,6 +647,7 @@ describe('global appearance tokens', () => { expect(appCss).toContain('--gn-font-size-mono: calc(var(--gonavi-font-size, 14px) * var(--gn-ui-scale, 1) * 0.92);'); expect(appCss).toContain('--gn-settings-font-secondary: var(--gn-font-size-sm);'); expect(appCss).toMatch(/\.gonavi-settings-center-modal \.ant-btn\s*\{[^}]*font-size:\s*var\(--gn-settings-font-caption\)/s); + expect(appCss).toMatch(/\.gonavi-settings-center-modal \.gonavi-settings-center-entry\.ant-btn\s*\{[^}]*font-size:\s*var\(--gn-settings-font-body\) !important;/s); expect(appCss).toMatch(/\.gonavi-settings-center-modal \.gonavi-ai-provider-add\.ant-btn\s*\{[^}]*height:\s*var\(--gn-control-height, 32px\) !important;/s); expect(appCss).toMatch(/\.gonavi-theme-settings \.gonavi-settings-section-hint\s*\{[^}]*font-size:\s*var\(--gn-settings-font-secondary/s); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 81d2cf58..5914de76 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3632,8 +3632,7 @@ function App() { const restartRequired = dataRootInfo?.logDirectoryRestartRequired === true; return (
-
{t('app.data_root.log_directory.title')}
-
+
{t('app.data_root.log_directory.description')}
@@ -6084,41 +6083,6 @@ function App() { /> ), })} - {renderThemeSettingsRow({ - label: ( - - {t('app.theme.data_table.font_size')} - - - ), - stacked: true, - control: ( - setAppearance({ - dataTableFontSize: sanitizeDataTableFontSize(value), - dataTableFontSizeFollowGlobal: false, - })} - /> - ), - })} {renderThemeSettingsRow({ label: ( @@ -6154,6 +6118,41 @@ function App() { /> ), })} + {renderThemeSettingsRow({ + label: ( + + {t('app.theme.data_table.font_size')} + + + ), + stacked: true, + control: ( + setAppearance({ + dataTableFontSize: sanitizeDataTableFontSize(value), + dataTableFontSizeFollowGlobal: false, + })} + /> + ), + })} {renderThemeSettingsRow({ label: ( @@ -7161,6 +7160,7 @@ function App() { ...toolCenterDetailPanelStyle, padding: '0 4px 0 0', border: 'none', + borderBottom: 'none', borderRadius: 0, background: 'transparent', }; @@ -8352,9 +8352,8 @@ function App() { textAlign: 'left', width: '100%', padding: '10px 6px 10px 12px', - borderRadius: 0, + borderRadius: 4, border: 'none', - borderBottom: `1px solid ${overlayTheme.divider}`, background: active ? overlayTheme.selectedBg : 'transparent', @@ -8423,7 +8422,7 @@ function App() { > {activeSettingsCenterPane ? (
-
+
{activeSettingsCenterPaneItem?.title ?? activeSettingsCenterGroup.title} @@ -8448,7 +8447,6 @@ function App() { gap: activeSettingsCenterPane.key === 'about-go-navi' ? 16 : 8, paddingTop: 10, marginTop: 10, - borderTop: `1px solid ${overlayTheme.divider}`, flexShrink: 0, }} > @@ -8474,17 +8472,13 @@ function App() {
{activeSettingsCenterGroup.description}
- {activeSettingsCenterGroup.items.map((item, index) => ( + {activeSettingsCenterGroup.items.map((item) => ( )} -
- {t('ai_settings.tools.summary', { - flowVisible: visibleFlows.length, - flowTotal: builtinToolFlows.length, - toolVisible: visibleTools.length, - toolTotal: builtinToolInfo.length, +
+ {catalogViews.map((view, viewIndex) => { + const active = activeView === view.key; + const ViewIcon = view.icon; + return ( + + ); })}
- {visibleFlows.length > 0 && ( -
- {visibleFlows.map((flow) => ( -
- - + +
+ {flow.description}
-
- {parameterDetails.map((item) => ( -
+ ))} +
+ ) : ( +
+ {t('ai_settings.tools.empty.no_flow_matches')} +
+ )} +
+ +
+ ); + })}
- - ); - })} + ) : ( +
+ {t('ai_settings.tools.empty.no_matches')} +
+ )} +
); }; diff --git a/frontend/src/components/ai/AIMCPClientInstallPanel.tsx b/frontend/src/components/ai/AIMCPClientInstallPanel.tsx index b725ce0a..2155bd80 100644 --- a/frontend/src/components/ai/AIMCPClientInstallPanel.tsx +++ b/frontend/src/components/ai/AIMCPClientInstallPanel.tsx @@ -60,7 +60,7 @@ const AIMCPClientInstallPanel: React.FC = ({ const selectedIsRemoteClient = isRemoteMCPClientStatus(selectedStatus); return ( -
+
{ + const React = await import('react'); + return { + CheckCircleFilled: (props: any) => React.createElement('span', props), + }; +}); + describe('AIMCPClientSelectorPanel', () => { it('renders local install and remote bridge choices with clear state labels', () => { const markup = renderToStaticMarkup( @@ -68,14 +75,14 @@ describe('AIMCPClientSelectorPanel', () => { expect(markup).toContain('Selected. The remote connection guide will be copied'); expect(markup).toContain('cloud Agents'); expect(markup).toContain('role="radiogroup"'); - expect(markup).toContain('class="gonavi-ai-mcp-client-option"'); + expect(markup).toContain('class="gonavi-ai-mcp-client-options"'); + expect(markup).toContain('class="gonavi-ai-mcp-client-option is-active"'); + expect(markup).toContain('class="gonavi-ai-mcp-client-check"'); expect(markup).toContain('role="radio"'); expect(markup).toContain('aria-checked="true"'); expect(markup.match(/tabindex="-1"/g)).toHaveLength(2); expect(markup.match(/tabindex="0"/g)).toHaveLength(1); - expect(markup).toContain('border-left:3px solid #1677ff'); - expect(markup).toContain('background:transparent'); - expect(markup).toContain('min-height:46px'); + expect(markup).not.toContain('border-left:3px solid'); expect(markup).toContain('class="gonavi-ai-mcp-disclosure gonavi-ai-mcp-client-guide-disclosure"'); expect(markup).not.toContain('gonavi-ai-mcp-client-guide-disclosure" open'); }); diff --git a/frontend/src/components/ai/AIMCPClientSelectorPanel.tsx b/frontend/src/components/ai/AIMCPClientSelectorPanel.tsx index 3d3b2073..77bf36be 100644 --- a/frontend/src/components/ai/AIMCPClientSelectorPanel.tsx +++ b/frontend/src/components/ai/AIMCPClientSelectorPanel.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { CheckCircleFilled } from '@ant-design/icons'; import type { AIMCPClientInstallStatus } from '../../types'; import { isMCPClientKey, @@ -53,7 +54,6 @@ const AIMCPClientSelectorPanel: React.FC = ({ selectedClient, darkMode, overlayTheme, - cardBorder, statusLoading, onSelectClient, }) => { @@ -87,92 +87,87 @@ const AIMCPClientSelectorPanel: React.FC = ({
{copy('ai_chat.mcp_client.install.selector.choice_title', 'Select external client')}
-
- {statuses.map((status, statusIndex) => { - const client = isMCPClientKey(status.client) ? status.client : 'claude-code'; - const remoteClient = isRemoteMCPClientStatus(status); - const active = selectedClient === client; - const tone = getMCPClientStatusTone(status, darkMode, t); - const optionSummary = getMCPClientOptionSummary(status, t); - const optionState = getMCPClientInstallStateLabel(status, t); - const optionHint = active - ? (remoteClient - ? copy('ai_chat.mcp_client.install.selector.hint.active_remote', 'Selected. The remote connection guide will be copied.') - : copy('ai_chat.mcp_client.install.selector.hint.active_local', 'Selected. Only this client will be written or updated.')) - : (remoteClient - ? copy('ai_chat.mcp_client.install.selector.hint.inactive_remote', 'Click to view the remote connection method.') - : copy('ai_chat.mcp_client.install.selector.hint.inactive_local', 'Click to switch to this client.')); - return ( - - ); - })} -
+ + {status.displayName} + + + {active && ( + + )} + + {tone.label} + + + + ); + })} +
diff --git a/frontend/src/components/ai/AIMCPClientStatusPanel.test.tsx b/frontend/src/components/ai/AIMCPClientStatusPanel.test.tsx index bbb5ed13..5cf72b1d 100644 --- a/frontend/src/components/ai/AIMCPClientStatusPanel.test.tsx +++ b/frontend/src/components/ai/AIMCPClientStatusPanel.test.tsx @@ -43,6 +43,7 @@ describe('AIMCPClientStatusPanel', () => { expect(markup).toContain('Refresh status'); expect(markup).toContain('Copy config path'); expect(markup).toContain('Copy launch command'); + expect(markup).toContain('class="gonavi-ai-mcp-client-status-panel"'); expect(markup).toContain('class="gonavi-ai-mcp-disclosure gonavi-ai-mcp-client-status-disclosure"'); expect(markup).not.toContain('gonavi-ai-mcp-client-status-disclosure" open'); }); diff --git a/frontend/src/components/ai/AIMCPClientStatusPanel.tsx b/frontend/src/components/ai/AIMCPClientStatusPanel.tsx index fb0bd2cf..e1935ed6 100644 --- a/frontend/src/components/ai/AIMCPClientStatusPanel.tsx +++ b/frontend/src/components/ai/AIMCPClientStatusPanel.tsx @@ -56,10 +56,8 @@ const AIMCPClientStatusPanel: React.FC = ({ return (
= ({ item, - cardBorder, darkMode, overlayTheme, compact = false, @@ -29,7 +28,6 @@ const AIMCPFieldGuideCard: React.FC = ({
= ({ status, draft, loading, - cardBorder, darkMode, overlayTheme, onDraftChange, @@ -58,7 +57,6 @@ const AIMCPHTTPServerPanel: React.FC = ({ className="gonavi-ai-mcp-http-panel" style={{ padding: '14px 0 0', - borderBottom: `1px solid ${cardBorder}`, background: 'transparent', display: 'flex', flexDirection: 'column', diff --git a/frontend/src/components/ai/AIMCPQuickAddServerPanel.tsx b/frontend/src/components/ai/AIMCPQuickAddServerPanel.tsx index 44c5d932..94ff4576 100644 --- a/frontend/src/components/ai/AIMCPQuickAddServerPanel.tsx +++ b/frontend/src/components/ai/AIMCPQuickAddServerPanel.tsx @@ -103,7 +103,6 @@ const AIMCPQuickAddServerPanel: React.FC = ({ className="gonavi-ai-mcp-quick-add" style={{ padding: '4px 0 14px', - borderBottom: `1px solid ${cardBorder}`, background: 'transparent', display: 'flex', flexDirection: 'column', @@ -125,7 +124,7 @@ const AIMCPQuickAddServerPanel: React.FC = ({
)}
-
@@ -154,8 +153,8 @@ const AIMCPQuickAddServerPanel: React.FC = ({ minHeight: 38, padding: '7px 9px', border: 'none', - borderBottom: `1px solid ${cardBorder}`, borderLeft: '3px solid transparent', + borderRadius: 4, background: 'transparent', color: overlayTheme.titleText, cursor: 'pointer', diff --git a/frontend/src/components/ai/AIMCPRemoteQuickStartPanel.tsx b/frontend/src/components/ai/AIMCPRemoteQuickStartPanel.tsx index 1314f98c..dd36cde7 100644 --- a/frontend/src/components/ai/AIMCPRemoteQuickStartPanel.tsx +++ b/frontend/src/components/ai/AIMCPRemoteQuickStartPanel.tsx @@ -20,7 +20,6 @@ interface RemoteCommandCardProps { children: React.ReactNode; darkMode: boolean; overlayTheme: OverlayWorkbenchTheme; - cardBorder: string; } const remoteCodeStyle = (overlayTheme: OverlayWorkbenchTheme): React.CSSProperties => ({ @@ -37,12 +36,10 @@ const RemoteCommandCard: React.FC = ({ title, children, overlayTheme, - cardBorder, }) => (
@@ -57,7 +54,6 @@ const AIMCPRemoteQuickStartPanel: React.FC = ({ quickStart, darkMode, overlayTheme, - cardBorder, }) => { const i18n = useOptionalI18n(); const copy = i18n?.t ?? ((key, params) => catalogTranslate('en-US', key, params)); @@ -67,7 +63,6 @@ const AIMCPRemoteQuickStartPanel: React.FC = ({
= ({ key={item.key} style={{ padding: '10px 10px 10px 0', - borderBottom: `1px solid ${cardBorder}`, background: 'transparent', display: 'flex', flexDirection: 'column', @@ -130,7 +124,6 @@ const AIMCPRemoteQuickStartPanel: React.FC = ({ title={copy('ai_settings.mcp_server.remote_quick_start.card.cloud_agent')} darkMode={darkMode} overlayTheme={overlayTheme} - cardBorder={cardBorder} > {quickStart.configJson} @@ -140,7 +133,6 @@ const AIMCPRemoteQuickStartPanel: React.FC = ({ title={copy('ai_settings.mcp_server.remote_quick_start.card.cli_config')} darkMode={darkMode} overlayTheme={overlayTheme} - cardBorder={cardBorder} > {quickStart.configCommand} @@ -155,7 +147,6 @@ const AIMCPRemoteQuickStartPanel: React.FC = ({ title={copy('ai_settings.mcp_server.remote_quick_start.card.windows_launch')} darkMode={darkMode} overlayTheme={overlayTheme} - cardBorder={cardBorder} > {quickStart.launchCommand} diff --git a/frontend/src/components/ai/AIMCPServerCard.tsx b/frontend/src/components/ai/AIMCPServerCard.tsx index ec06f900..2e7940e2 100644 --- a/frontend/src/components/ai/AIMCPServerCard.tsx +++ b/frontend/src/components/ai/AIMCPServerCard.tsx @@ -75,7 +75,7 @@ export const AIMCPServerCard: React.FC = ({ className="gonavi-ai-mcp-server-row gonavi-ai-mcp-disclosure" open={expanded} onToggle={(event) => setExpanded(event.currentTarget.open)} - style={{ borderLeft: `3px solid ${overlayTheme.selectedText}`, borderBottom: `1px solid ${cardBorder}`, background: 'transparent' }} + style={{ borderLeft: `3px solid ${overlayTheme.selectedText}`, borderRadius: 4, background: 'transparent' }} > diff --git a/frontend/src/components/ai/AIMCPServerFormPanel.tsx b/frontend/src/components/ai/AIMCPServerFormPanel.tsx index 9dc51345..cdc252e1 100644 --- a/frontend/src/components/ai/AIMCPServerFormPanel.tsx +++ b/frontend/src/components/ai/AIMCPServerFormPanel.tsx @@ -207,7 +207,7 @@ const AIMCPServerFormPanel: React.FC = ({ overlayTheme={overlayTheme} /> -
+
{copy('ai_settings.mcp_server.form.instructions.title')}
{copy('ai_settings.mcp_server.form.instructions.test_title')} diff --git a/frontend/src/components/ai/AISettingsChoiceGroup.tsx b/frontend/src/components/ai/AISettingsChoiceGroup.tsx index e1493190..7b08457e 100644 --- a/frontend/src/components/ai/AISettingsChoiceGroup.tsx +++ b/frontend/src/components/ai/AISettingsChoiceGroup.tsx @@ -7,6 +7,7 @@ export interface AISettingsChoiceOption { title: string; description: string; icon: React.ReactNode; + iconColor: string; } interface AISettingsChoiceGroupProps { @@ -58,7 +59,8 @@ const AISettingsChoiceGroup = ({ role="radiogroup" aria-label={ariaLabel} style={{ - borderTop: `1px solid ${cardBorder}`, + display: 'grid', + gap: 2, fontFamily: 'var(--gn-font-sans)', }} > @@ -90,8 +92,7 @@ const AISettingsChoiceGroup = ({ minHeight: 'calc(62px * var(--gn-ui-scale, 1))', padding: '11px 10px', border: 'none', - borderBottom: `1px solid ${cardBorder}`, - borderRadius: 0, + borderRadius: 4, cursor: 'pointer', transition: 'background 0.16s ease, outline-color 0.16s ease', background: active ? overlayTheme.selectedBg : (interactive ? overlayTheme.hoverBg : 'transparent'), @@ -110,6 +111,7 @@ const AISettingsChoiceGroup = ({ >