Skip to content

Commit 620cf3d

Browse files
committed
Ensures the gear icon in slash commands goes to the right place in settings
1 parent f4ab67a commit 620cf3d

File tree

4 files changed

+166
-3
lines changed

4 files changed

+166
-3
lines changed

src/core/webview/webviewMessageHandler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2776,7 +2776,12 @@ export const webviewMessageHandler = async (
27762776
TelemetryService.instance.captureTabShown(message.tab)
27772777
}
27782778

2779-
await provider.postMessageToWebview({ type: "action", action: "switchTab", tab: message.tab })
2779+
await provider.postMessageToWebview({
2780+
type: "action",
2781+
action: "switchTab",
2782+
tab: message.tab,
2783+
values: message.values,
2784+
})
27802785
}
27812786
break
27822787
}

webview-ui/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ const App = () => {
143143
if (message.action === "switchTab" && message.tab) {
144144
const targetTab = message.tab as Tab
145145
switchTab(targetTab)
146-
setCurrentSection(undefined)
146+
// Extract targetSection from values if provided
147+
const targetSection = message.values?.section as string | undefined
148+
setCurrentSection(targetSection)
147149
setCurrentMarketplaceTab(undefined)
148150
} else {
149151
// Handle other actions using the mapping
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import React from "react"
2+
import { render, waitFor } from "@testing-library/react"
3+
import { vi } from "vitest"
4+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
5+
6+
import App from "../App"
7+
import TranslationProvider from "../i18n/TranslationContext"
8+
9+
// Mock vscode API
10+
const mockPostMessage = vi.fn()
11+
vi.mock("../utils/vscode", () => ({
12+
vscode: {
13+
postMessage: (message: any) => mockPostMessage(message),
14+
},
15+
}))
16+
17+
// Mock extension state
18+
const mockExtensionState = {
19+
didHydrateState: true,
20+
showWelcome: false,
21+
shouldShowAnnouncement: false,
22+
telemetrySetting: "off" as const,
23+
telemetryKey: undefined,
24+
machineId: "test-machine-id",
25+
cloudUserInfo: null,
26+
cloudIsAuthenticated: false,
27+
cloudApiUrl: undefined,
28+
renderContext: "editor" as const,
29+
mdmCompliant: true,
30+
currentApiConfigName: "test-config",
31+
listApiConfigMeta: [],
32+
apiConfiguration: {},
33+
experiments: {},
34+
customModes: [],
35+
mode: { slug: "code", name: "Code" },
36+
clineMessages: [],
37+
taskHistory: [],
38+
version: "1.0.0",
39+
writeDelayMs: 100,
40+
requestDelaySeconds: 1,
41+
enableCheckpoints: false,
42+
maxOpenTabsContext: 10,
43+
maxWorkspaceFiles: 100,
44+
showRooIgnoredFiles: false,
45+
maxReadFileLine: 1000,
46+
maxImageFileSize: 5,
47+
maxTotalImageSize: 20,
48+
mcpEnabled: false,
49+
enableMcpServerCreation: false,
50+
sharingEnabled: false,
51+
organizationAllowList: {
52+
enabled: false,
53+
allowed: [],
54+
providers: {},
55+
},
56+
autoCondenseContext: false,
57+
autoCondenseContextPercent: 50,
58+
profileThresholds: {},
59+
hasOpenedModeSelector: false,
60+
remoteControlEnabled: false,
61+
taskSyncEnabled: false,
62+
featureRoomoteControlEnabled: false,
63+
// Add missing properties required by ChatView components
64+
openedTabs: [],
65+
filePaths: [],
66+
commands: [],
67+
gitCommits: [],
68+
browserToolEnabled: false,
69+
mcpServers: [],
70+
}
71+
72+
vi.mock("../context/ExtensionStateContext", () => ({
73+
ExtensionStateContextProvider: ({ children }: { children: React.ReactNode }) => children,
74+
useExtensionState: () => mockExtensionState,
75+
}))
76+
77+
describe("Settings Tab Navigation", () => {
78+
let queryClient: QueryClient
79+
80+
beforeEach(() => {
81+
queryClient = new QueryClient({
82+
defaultOptions: {
83+
queries: { retry: false },
84+
mutations: { retry: false },
85+
},
86+
})
87+
mockPostMessage.mockClear()
88+
})
89+
90+
it("should navigate to slash commands section when handleSettingsClick is called", async () => {
91+
const { container } = render(
92+
<QueryClientProvider client={queryClient}>
93+
<TranslationProvider>
94+
<App />
95+
</TranslationProvider>
96+
</QueryClientProvider>,
97+
)
98+
99+
// Simulate message from ContextMenu to switch to settings tab with targetSection
100+
const messageEvent = new MessageEvent("message", {
101+
data: {
102+
type: "action",
103+
action: "switchTab",
104+
tab: "settings",
105+
values: { section: "slashCommands" },
106+
},
107+
})
108+
window.dispatchEvent(messageEvent)
109+
110+
// Wait for the settings view to render
111+
await waitFor(() => {
112+
const slashCommandsTab = container.querySelector('[data-testid="tab-slashCommands"]')
113+
expect(slashCommandsTab).toBeTruthy()
114+
})
115+
116+
// Verify the slash commands tab is active
117+
const slashCommandsTab = container.querySelector('[data-testid="tab-slashCommands"]')
118+
expect(slashCommandsTab?.getAttribute("aria-selected")).toBe("true")
119+
})
120+
121+
it("should switch to settings tab without a specific section", async () => {
122+
const { container } = render(
123+
<QueryClientProvider client={queryClient}>
124+
<TranslationProvider>
125+
<App />
126+
</TranslationProvider>
127+
</QueryClientProvider>,
128+
)
129+
130+
// Simulate message to switch to settings tab without targetSection
131+
const messageEvent = new MessageEvent("message", {
132+
data: {
133+
type: "action",
134+
action: "switchTab",
135+
tab: "settings",
136+
},
137+
})
138+
window.dispatchEvent(messageEvent)
139+
140+
// Wait for the settings view to render
141+
await waitFor(() => {
142+
const providersTab = container.querySelector('[data-testid="tab-providers"]')
143+
expect(providersTab).toBeTruthy()
144+
})
145+
146+
// Verify the default providers tab is active
147+
const providersTab = container.querySelector('[data-testid="tab-providers"]')
148+
expect(providersTab?.getAttribute("aria-selected")).toBe("true")
149+
})
150+
})

webview-ui/src/components/chat/ContextMenu.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
253253
)
254254
}
255255

256-
const handleSettingsClick = () => {
256+
const handleSettingsClick = (e: React.MouseEvent) => {
257+
// Prevent any default behavior
258+
e.preventDefault()
257259
// Switch to settings tab and navigate to slash commands section
258260
vscode.postMessage({
259261
type: "switchTab",
@@ -300,6 +302,10 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
300302
<span style={{ fontSize: "0.85em", opacity: 0.8 }}>Slash Commands</span>
301303
<button
302304
onClick={handleSettingsClick}
305+
onMouseDown={(e) => {
306+
e.stopPropagation()
307+
e.preventDefault()
308+
}}
303309
style={{
304310
background: "transparent",
305311
border: "none",

0 commit comments

Comments
 (0)