mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-19 13:33:35 +08:00
refactor(desktop): move trace entry into Settings
Trace is a low-frequency diagnostic feature, so its entry points no longer sit in primary chrome: - Remove the Trace nav item above the session list in the sidebar - Remove the trace open/open-window buttons from the session header - Add a Trace tab in Settings between Token usage and Diagnostics, embedding the existing TraceList page full-bleed - Add settings.tab.trace and drop unused sidebar.traces across locales
This commit is contained in:
parent
d3d7566f0c
commit
d9ce2f09e1
@ -94,6 +94,10 @@ vi.mock('../pages/ActivitySettings', () => ({
|
|||||||
ActivitySettings: () => <div>Activity Settings Mock</div>,
|
ActivitySettings: () => <div>Activity Settings Mock</div>,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
vi.mock('../pages/TraceList', () => ({
|
||||||
|
TraceList: () => <div>Trace List Mock</div>,
|
||||||
|
}))
|
||||||
|
|
||||||
vi.mock('../stores/agentStore', () => ({
|
vi.mock('../stores/agentStore', () => ({
|
||||||
useAgentStore: () => ({
|
useAgentStore: () => ({
|
||||||
activeAgents: [],
|
activeAgents: [],
|
||||||
@ -677,6 +681,20 @@ describe('Settings > General tab', () => {
|
|||||||
expect(screen.getByText('Activity Settings Mock')).toBeInTheDocument()
|
expect(screen.getByText('Activity Settings Mock')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('opens the Trace tab from Settings navigation between Token usage and Diagnostics', () => {
|
||||||
|
render(<Settings />)
|
||||||
|
|
||||||
|
const usageTab = screen.getByText('Token usage')
|
||||||
|
const traceTab = screen.getByText('Trace')
|
||||||
|
const diagnosticsTab = screen.getByText('Diagnostics')
|
||||||
|
expect((usageTab.compareDocumentPosition(traceTab) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0).toBe(true)
|
||||||
|
expect((traceTab.compareDocumentPosition(diagnosticsTab) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0).toBe(true)
|
||||||
|
|
||||||
|
fireEvent.click(traceTab)
|
||||||
|
|
||||||
|
expect(screen.getByText('Trace List Mock')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
it('lets the user disable WebFetch preflight skipping', () => {
|
it('lets the user disable WebFetch preflight skipping', () => {
|
||||||
render(<Settings />)
|
render(<Settings />)
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useUIStore } from '../../stores/uiStore'
|
|||||||
import { useTranslation, type TranslationKey } from '../../i18n'
|
import { useTranslation, type TranslationKey } from '../../i18n'
|
||||||
import { ConfirmDialog } from '../shared/ConfirmDialog'
|
import { ConfirmDialog } from '../shared/ConfirmDialog'
|
||||||
import type { SessionListItem } from '../../types/session'
|
import type { SessionListItem } from '../../types/session'
|
||||||
import { useTabStore, SETTINGS_TAB_ID, SCHEDULED_TAB_ID, TRACE_LIST_TAB_ID } from '../../stores/tabStore'
|
import { useTabStore, SETTINGS_TAB_ID, SCHEDULED_TAB_ID } from '../../stores/tabStore'
|
||||||
import { useChatStore } from '../../stores/chatStore'
|
import { useChatStore } from '../../stores/chatStore'
|
||||||
import { useOpenTargetStore } from '../../stores/openTargetStore'
|
import { useOpenTargetStore } from '../../stores/openTargetStore'
|
||||||
import { desktopUiPreferencesApi, type SidebarProjectPreferences } from '../../api/desktopUiPreferences'
|
import { desktopUiPreferencesApi, type SidebarProjectPreferences } from '../../api/desktopUiPreferences'
|
||||||
@ -686,21 +686,6 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {
|
|||||||
{t('sidebar.scheduled')}
|
{t('sidebar.scheduled')}
|
||||||
</NavItem>
|
</NavItem>
|
||||||
)}
|
)}
|
||||||
{!isMobile && (
|
|
||||||
<NavItem
|
|
||||||
active={activeTabId === TRACE_LIST_TAB_ID}
|
|
||||||
collapsed={!expanded}
|
|
||||||
label={t('sidebar.traces')}
|
|
||||||
touchFriendly={isMobile}
|
|
||||||
onClick={() => {
|
|
||||||
useTabStore.getState().openTracesTab(t('sidebar.traces'))
|
|
||||||
closeMobileDrawer()
|
|
||||||
}}
|
|
||||||
icon={<span className="material-symbols-outlined text-[18px]">account_tree</span>}
|
|
||||||
>
|
|
||||||
{t('sidebar.traces')}
|
|
||||||
</NavItem>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
|
|||||||
@ -21,7 +21,6 @@ export const en = {
|
|||||||
// ─── Sidebar ──────────────────────────────────────
|
// ─── Sidebar ──────────────────────────────────────
|
||||||
'sidebar.newSession': 'New session',
|
'sidebar.newSession': 'New session',
|
||||||
'sidebar.scheduled': 'Scheduled',
|
'sidebar.scheduled': 'Scheduled',
|
||||||
'sidebar.traces': 'Trace',
|
|
||||||
'sidebar.terminal': 'Terminal',
|
'sidebar.terminal': 'Terminal',
|
||||||
'sidebar.settings': 'Settings',
|
'sidebar.settings': 'Settings',
|
||||||
'sidebar.searchPlaceholder': 'Search sessions...',
|
'sidebar.searchPlaceholder': 'Search sessions...',
|
||||||
@ -171,6 +170,7 @@ export const en = {
|
|||||||
'settings.tab.providers': 'Providers',
|
'settings.tab.providers': 'Providers',
|
||||||
'settings.tab.permissions': 'Permissions',
|
'settings.tab.permissions': 'Permissions',
|
||||||
'settings.tab.activity': 'Token usage',
|
'settings.tab.activity': 'Token usage',
|
||||||
|
'settings.tab.trace': 'Trace',
|
||||||
'settings.tab.general': 'General',
|
'settings.tab.general': 'General',
|
||||||
'settings.tab.h5Access': 'H5 Access',
|
'settings.tab.h5Access': 'H5 Access',
|
||||||
'settings.tab.terminal': 'Terminal',
|
'settings.tab.terminal': 'Terminal',
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export const jp: Record<TranslationKey, string> = {
|
|||||||
// ─── Sidebar ──────────────────────────────────────
|
// ─── Sidebar ──────────────────────────────────────
|
||||||
'sidebar.newSession': '新しいセッション',
|
'sidebar.newSession': '新しいセッション',
|
||||||
'sidebar.scheduled': 'スケジュール',
|
'sidebar.scheduled': 'スケジュール',
|
||||||
'sidebar.traces': 'Trace',
|
|
||||||
'sidebar.terminal': 'ターミナル',
|
'sidebar.terminal': 'ターミナル',
|
||||||
'sidebar.settings': '設定',
|
'sidebar.settings': '設定',
|
||||||
'sidebar.searchPlaceholder': 'セッションを検索...',
|
'sidebar.searchPlaceholder': 'セッションを検索...',
|
||||||
@ -173,6 +172,7 @@ export const jp: Record<TranslationKey, string> = {
|
|||||||
'settings.tab.providers': 'プロバイダー',
|
'settings.tab.providers': 'プロバイダー',
|
||||||
'settings.tab.permissions': '権限',
|
'settings.tab.permissions': '権限',
|
||||||
'settings.tab.activity': 'トークン使用量',
|
'settings.tab.activity': 'トークン使用量',
|
||||||
|
'settings.tab.trace': 'Trace',
|
||||||
'settings.tab.general': '一般',
|
'settings.tab.general': '一般',
|
||||||
'settings.tab.h5Access': 'H5 アクセス',
|
'settings.tab.h5Access': 'H5 アクセス',
|
||||||
'settings.tab.terminal': 'ターミナル',
|
'settings.tab.terminal': 'ターミナル',
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export const kr: Record<TranslationKey, string> = {
|
|||||||
// ─── Sidebar ──────────────────────────────────────
|
// ─── Sidebar ──────────────────────────────────────
|
||||||
'sidebar.newSession': '새 세션',
|
'sidebar.newSession': '새 세션',
|
||||||
'sidebar.scheduled': '예약 작업',
|
'sidebar.scheduled': '예약 작업',
|
||||||
'sidebar.traces': 'Trace',
|
|
||||||
'sidebar.terminal': '터미널',
|
'sidebar.terminal': '터미널',
|
||||||
'sidebar.settings': '설정',
|
'sidebar.settings': '설정',
|
||||||
'sidebar.searchPlaceholder': '세션 검색...',
|
'sidebar.searchPlaceholder': '세션 검색...',
|
||||||
@ -173,6 +172,7 @@ export const kr: Record<TranslationKey, string> = {
|
|||||||
'settings.tab.providers': '공급자',
|
'settings.tab.providers': '공급자',
|
||||||
'settings.tab.permissions': '권한',
|
'settings.tab.permissions': '권한',
|
||||||
'settings.tab.activity': '토큰 사용량',
|
'settings.tab.activity': '토큰 사용량',
|
||||||
|
'settings.tab.trace': 'Trace',
|
||||||
'settings.tab.general': '일반',
|
'settings.tab.general': '일반',
|
||||||
'settings.tab.h5Access': 'H5 액세스',
|
'settings.tab.h5Access': 'H5 액세스',
|
||||||
'settings.tab.terminal': '터미널',
|
'settings.tab.terminal': '터미널',
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export const zh: Record<TranslationKey, string> = {
|
|||||||
// ─── Sidebar ──────────────────────────────────────
|
// ─── Sidebar ──────────────────────────────────────
|
||||||
'sidebar.newSession': '新建會話',
|
'sidebar.newSession': '新建會話',
|
||||||
'sidebar.scheduled': '定時任務',
|
'sidebar.scheduled': '定時任務',
|
||||||
'sidebar.traces': 'Trace',
|
|
||||||
'sidebar.terminal': '終端',
|
'sidebar.terminal': '終端',
|
||||||
'sidebar.settings': '設定',
|
'sidebar.settings': '設定',
|
||||||
'sidebar.searchPlaceholder': '搜尋會話...',
|
'sidebar.searchPlaceholder': '搜尋會話...',
|
||||||
@ -173,6 +172,7 @@ export const zh: Record<TranslationKey, string> = {
|
|||||||
'settings.tab.providers': '服務商',
|
'settings.tab.providers': '服務商',
|
||||||
'settings.tab.permissions': '許可權',
|
'settings.tab.permissions': '許可權',
|
||||||
'settings.tab.activity': 'Token 用量',
|
'settings.tab.activity': 'Token 用量',
|
||||||
|
'settings.tab.trace': 'Trace',
|
||||||
'settings.tab.general': '通用',
|
'settings.tab.general': '通用',
|
||||||
'settings.tab.h5Access': 'H5 訪問',
|
'settings.tab.h5Access': 'H5 訪問',
|
||||||
'settings.tab.terminal': '終端',
|
'settings.tab.terminal': '終端',
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export const zh: Record<TranslationKey, string> = {
|
|||||||
// ─── Sidebar ──────────────────────────────────────
|
// ─── Sidebar ──────────────────────────────────────
|
||||||
'sidebar.newSession': '新建会话',
|
'sidebar.newSession': '新建会话',
|
||||||
'sidebar.scheduled': '定时任务',
|
'sidebar.scheduled': '定时任务',
|
||||||
'sidebar.traces': 'Trace',
|
|
||||||
'sidebar.terminal': '终端',
|
'sidebar.terminal': '终端',
|
||||||
'sidebar.settings': '设置',
|
'sidebar.settings': '设置',
|
||||||
'sidebar.searchPlaceholder': '搜索会话...',
|
'sidebar.searchPlaceholder': '搜索会话...',
|
||||||
@ -173,6 +172,7 @@ export const zh: Record<TranslationKey, string> = {
|
|||||||
'settings.tab.providers': '服务商',
|
'settings.tab.providers': '服务商',
|
||||||
'settings.tab.permissions': '权限',
|
'settings.tab.permissions': '权限',
|
||||||
'settings.tab.activity': 'Token 用量',
|
'settings.tab.activity': 'Token 用量',
|
||||||
|
'settings.tab.trace': 'Trace',
|
||||||
'settings.tab.general': '通用',
|
'settings.tab.general': '通用',
|
||||||
'settings.tab.h5Access': 'H5 访问',
|
'settings.tab.h5Access': 'H5 访问',
|
||||||
'settings.tab.terminal': '终端',
|
'settings.tab.terminal': '终端',
|
||||||
|
|||||||
@ -186,67 +186,6 @@ describe('ActiveSession task polling', () => {
|
|||||||
expect(screen.getByTestId('chat-input')).toHaveAttribute('data-variant', 'default')
|
expect(screen.getByTestId('chat-input')).toHaveAttribute('data-variant', 'default')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('opens the current session trace in a separate live window', () => {
|
|
||||||
const sessionId = 'trace-window-session'
|
|
||||||
const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null)
|
|
||||||
|
|
||||||
useSessionStore.setState({
|
|
||||||
sessions: [{
|
|
||||||
id: sessionId,
|
|
||||||
title: 'Trace Window Session',
|
|
||||||
createdAt: '2026-05-07T00:00:00.000Z',
|
|
||||||
modifiedAt: '2026-05-07T00:00:00.000Z',
|
|
||||||
messageCount: 1,
|
|
||||||
projectPath: '/workspace/project',
|
|
||||||
workDir: '/workspace/project',
|
|
||||||
workDirExists: true,
|
|
||||||
}],
|
|
||||||
activeSessionId: sessionId,
|
|
||||||
isLoading: false,
|
|
||||||
error: null,
|
|
||||||
})
|
|
||||||
useTabStore.setState({
|
|
||||||
tabs: [{ sessionId, title: 'Trace Window Session', type: 'session', status: 'idle' }],
|
|
||||||
activeTabId: sessionId,
|
|
||||||
})
|
|
||||||
useChatStore.setState({
|
|
||||||
sessions: {
|
|
||||||
[sessionId]: {
|
|
||||||
messages: [{ id: 'msg-1', type: 'assistant_text', content: 'hello', timestamp: 1 }],
|
|
||||||
chatState: 'idle',
|
|
||||||
connectionState: 'connected',
|
|
||||||
streamingText: '',
|
|
||||||
streamingToolInput: '',
|
|
||||||
activeToolUseId: null,
|
|
||||||
activeToolName: null,
|
|
||||||
activeThinkingId: null,
|
|
||||||
pendingPermission: null,
|
|
||||||
pendingComputerUsePermission: null,
|
|
||||||
tokenUsage: { input_tokens: 0, output_tokens: 0 },
|
|
||||||
elapsedSeconds: 0,
|
|
||||||
statusVerb: '',
|
|
||||||
slashCommands: [],
|
|
||||||
agentTaskNotifications: {},
|
|
||||||
elapsedTimer: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
render(<ActiveSession />)
|
|
||||||
fireEvent.click(screen.getByLabelText(/独立|separate/i))
|
|
||||||
|
|
||||||
expect(openSpy).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining(`traceSessionId=${sessionId}`),
|
|
||||||
'_blank',
|
|
||||||
'noopener,noreferrer',
|
|
||||||
)
|
|
||||||
expect(openSpy.mock.calls[0]?.[0]).toContain('traceWindow=1')
|
|
||||||
} finally {
|
|
||||||
openSpy.mockRestore()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders the current goal as a lightweight header strip without a page-level panel', () => {
|
it('renders the current goal as a lightweight header strip without a page-level panel', () => {
|
||||||
const sessionId = 'goal-visible-session'
|
const sessionId = 'goal-visible-session'
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { ExternalLink, RadioTower, Target } from 'lucide-react'
|
import { Target } from 'lucide-react'
|
||||||
import {
|
import {
|
||||||
SCHEDULED_TAB_ID,
|
SCHEDULED_TAB_ID,
|
||||||
SETTINGS_TAB_ID,
|
SETTINGS_TAB_ID,
|
||||||
@ -32,8 +32,6 @@ import type { ActiveGoalState } from '../types/chat'
|
|||||||
import { useMobileViewport } from '../hooks/useMobileViewport'
|
import { useMobileViewport } from '../hooks/useMobileViewport'
|
||||||
import { isDesktopRuntime } from '../lib/desktopRuntime'
|
import { isDesktopRuntime } from '../lib/desktopRuntime'
|
||||||
import { publicAssetPath } from '../lib/publicAsset'
|
import { publicAssetPath } from '../lib/publicAsset'
|
||||||
import { getDesktopHost } from '../lib/desktopHost'
|
|
||||||
import { buildTraceWindowUrl } from '../lib/traceLaunch'
|
|
||||||
|
|
||||||
const TASK_POLL_INTERVAL_MS = 1000
|
const TASK_POLL_INTERVAL_MS = 1000
|
||||||
const WORKSPACE_RESIZE_STEP = 32
|
const WORKSPACE_RESIZE_STEP = 32
|
||||||
@ -364,22 +362,6 @@ export function ActiveSession() {
|
|||||||
return t('session.timeDays', { n: Math.floor(diff / 86400000) })
|
return t('session.timeDays', { n: Math.floor(diff / 86400000) })
|
||||||
}, [session?.modifiedAt, t])
|
}, [session?.modifiedAt, t])
|
||||||
|
|
||||||
const openTrace = () => {
|
|
||||||
if (!activeTabId) return
|
|
||||||
const title = session?.title || t('session.untitled')
|
|
||||||
useTabStore.getState().openTraceTab(activeTabId, `${t('trace.title')}: ${title}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const openTraceWindow = () => {
|
|
||||||
if (!activeTabId) return
|
|
||||||
const host = getDesktopHost()
|
|
||||||
if (host.trace) {
|
|
||||||
void host.trace.openWindow(activeTabId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
window.open(buildTraceWindowUrl(activeTabId), '_blank', 'noopener,noreferrer')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!activeTabId) return null
|
if (!activeTabId) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -480,25 +462,6 @@ export function ActiveSession() {
|
|||||||
>
|
>
|
||||||
{session?.title || t('session.untitled')}
|
{session?.title || t('session.untitled')}
|
||||||
</h1>
|
</h1>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={t('trace.open')}
|
|
||||||
title={t('trace.open')}
|
|
||||||
onClick={openTrace}
|
|
||||||
className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-[8px] border border-[var(--color-border)] px-2.5 text-xs font-semibold text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border-focus)] hover:text-[var(--color-text-primary)] active:scale-[0.98]"
|
|
||||||
>
|
|
||||||
<RadioTower size={14} strokeWidth={2} aria-hidden="true" />
|
|
||||||
<span className={showRightPanel ? 'sr-only' : 'hidden sm:inline'}>{t('trace.open')}</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={t('trace.openWindow')}
|
|
||||||
title={t('trace.openWindow')}
|
|
||||||
onClick={openTraceWindow}
|
|
||||||
className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-[8px] border border-[var(--color-border)] text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border-focus)] hover:text-[var(--color-text-primary)] active:scale-[0.98]"
|
|
||||||
>
|
|
||||||
<ExternalLink size={14} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import { ComputerUseSettings } from './ComputerUseSettings'
|
|||||||
import { McpSettings } from './McpSettings'
|
import { McpSettings } from './McpSettings'
|
||||||
import { TerminalSettings } from './TerminalSettings'
|
import { TerminalSettings } from './TerminalSettings'
|
||||||
import { DiagnosticsSettings } from './DiagnosticsSettings'
|
import { DiagnosticsSettings } from './DiagnosticsSettings'
|
||||||
|
import { TraceList } from './TraceList'
|
||||||
import { ActivitySettings } from './ActivitySettings'
|
import { ActivitySettings } from './ActivitySettings'
|
||||||
import { MemorySettings } from './MemorySettings'
|
import { MemorySettings } from './MemorySettings'
|
||||||
import { useUIStore, type SettingsTab } from '../stores/uiStore'
|
import { useUIStore, type SettingsTab } from '../stores/uiStore'
|
||||||
@ -166,6 +167,7 @@ export function Settings() {
|
|||||||
<TabButton icon="extension" label={t('settings.tab.plugins')} active={activeTab === 'plugins'} onClick={() => setActiveTab('plugins')} />
|
<TabButton icon="extension" label={t('settings.tab.plugins')} active={activeTab === 'plugins'} onClick={() => setActiveTab('plugins')} />
|
||||||
<TabButton icon="mouse" label={t('settings.tab.computerUse')} active={activeTab === 'computerUse'} onClick={() => setActiveTab('computerUse')} />
|
<TabButton icon="mouse" label={t('settings.tab.computerUse')} active={activeTab === 'computerUse'} onClick={() => setActiveTab('computerUse')} />
|
||||||
<TabButton icon="monitoring" label={t('settings.tab.activity')} active={activeTab === 'activity'} onClick={() => setActiveTab('activity')} />
|
<TabButton icon="monitoring" label={t('settings.tab.activity')} active={activeTab === 'activity'} onClick={() => setActiveTab('activity')} />
|
||||||
|
<TabButton icon="account_tree" label={t('settings.tab.trace')} active={activeTab === 'trace'} onClick={() => setActiveTab('trace')} />
|
||||||
<TabButton icon="monitor_heart" label={t('settings.tab.diagnostics')} active={activeTab === 'diagnostics'} onClick={() => setActiveTab('diagnostics')} />
|
<TabButton icon="monitor_heart" label={t('settings.tab.diagnostics')} active={activeTab === 'diagnostics'} onClick={() => setActiveTab('diagnostics')} />
|
||||||
</div>
|
</div>
|
||||||
<div className="border-t border-[var(--color-border)]/40 pt-1">
|
<div className="border-t border-[var(--color-border)]/40 pt-1">
|
||||||
@ -173,8 +175,8 @@ export function Settings() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tab content */}
|
{/* Tab content; trace embeds a full-bleed page that manages its own scroll */}
|
||||||
<div className="flex-1 overflow-y-auto px-8 py-6">
|
<div className={activeTab === 'trace' ? 'flex-1 flex min-h-0 flex-col overflow-hidden' : 'flex-1 overflow-y-auto px-8 py-6'}>
|
||||||
{activeTab === 'providers' && <ProviderSettings />}
|
{activeTab === 'providers' && <ProviderSettings />}
|
||||||
{activeTab === 'activity' && <ActivitySettings />}
|
{activeTab === 'activity' && <ActivitySettings />}
|
||||||
{activeTab === 'general' && <GeneralSettings />}
|
{activeTab === 'general' && <GeneralSettings />}
|
||||||
@ -187,6 +189,7 @@ export function Settings() {
|
|||||||
{activeTab === 'memory' && <MemorySettings />}
|
{activeTab === 'memory' && <MemorySettings />}
|
||||||
{activeTab === 'plugins' && <PluginSettings />}
|
{activeTab === 'plugins' && <PluginSettings />}
|
||||||
{activeTab === 'computerUse' && <ComputerUseSettings />}
|
{activeTab === 'computerUse' && <ComputerUseSettings />}
|
||||||
|
{activeTab === 'trace' && <TraceList />}
|
||||||
{activeTab === 'diagnostics' && <DiagnosticsSettings />}
|
{activeTab === 'diagnostics' && <DiagnosticsSettings />}
|
||||||
{activeTab === 'about' && <AboutSettings />}
|
{activeTab === 'about' && <AboutSettings />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export type SettingsTab =
|
|||||||
| 'memory'
|
| 'memory'
|
||||||
| 'plugins'
|
| 'plugins'
|
||||||
| 'computerUse'
|
| 'computerUse'
|
||||||
|
| 'trace'
|
||||||
| 'diagnostics'
|
| 'diagnostics'
|
||||||
| 'about'
|
| 'about'
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user