Compare commits

...

6 Commits

Author SHA1 Message Date
Elephant Lumps 7679d5e9cc merge conflicts 2025-06-04 18:15:17 -07:00
Elephant Lumps d0c93d714a add provider type filtering 2025-06-02 13:10:59 -07:00
Elephant Lumps 8b5df83f1d merge conflicts 2025-06-02 12:43:34 -07:00
Elephant Lumps 8bdc41b0fb Merge branch 'main' into migrate-setttingsButtonClicked-protobus 2025-06-01 21:30:28 -07:00
Elephant Lumps 2e9894e482 changeset 2025-06-01 11:03:05 -07:00
Elephant Lumps 3253ee84b7 migrate settingsButtonClicked 2025-06-01 11:02:25 -07:00
6 changed files with 103 additions and 24 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Migrate settingsButtonClicked to protobus
+3
View File
@@ -40,4 +40,7 @@ service UiService {
// Subscribe to account button click events
rpc subscribeToAccountButtonClicked(EmptyRequest) returns (stream Empty);
// Subscribe to settings button clicked events
rpc subscribeToSettingsButtonClicked(WebviewProviderTypeRequest) returns (stream Empty);
}
@@ -0,0 +1,61 @@
import { Empty } from "@shared/proto/common"
import { WebviewProviderType, WebviewProviderTypeRequest } from "@shared/proto/ui"
import { StreamingResponseHandler, getRequestRegistry } from "../grpc-handler"
import type { Controller } from "../index"
// Track subscriptions with their provider type
const subscriptions = new Map<StreamingResponseHandler, WebviewProviderType>()
/**
* Subscribe to settings button clicked events
* @param controller The controller instance
* @param request The request with provider type
* @param responseStream The streaming response handler
* @param requestId The ID of the request (passed by the gRPC handler)
*/
export async function subscribeToSettingsButtonClicked(
controller: Controller,
request: WebviewProviderTypeRequest,
responseStream: StreamingResponseHandler,
requestId?: string,
): Promise<void> {
const providerType = request.providerType
console.log(`[DEBUG] set up settings button subscription for ${WebviewProviderType[providerType]} webview`)
// Store the subscription with its provider type
subscriptions.set(responseStream, providerType)
// Register cleanup when the connection is closed
const cleanup = () => {
subscriptions.delete(responseStream)
}
// Register the cleanup function with the request registry if we have a requestId
if (requestId) {
getRequestRegistry().registerRequest(requestId, cleanup, { type: "settings_button_clicked_subscription" }, responseStream)
}
}
/**
* Send a settings button clicked event to active subscribers of matching provider type
* @param webviewType The type of webview that triggered the event
*/
export async function sendSettingsButtonClickedEvent(webviewType?: WebviewProviderType): Promise<void> {
// Process all subscriptions, filtering based on the source
const promises = Array.from(subscriptions.entries()).map(async ([responseStream, providerType]) => {
// If webviewType is provided, only send to subscribers of the same type
if (webviewType !== undefined && webviewType !== providerType) {
return // Skip subscribers of different types
}
try {
const event = Empty.create({})
await responseStream(event, false) // Not the last message
} catch (error) {
console.error(`Error sending settings button clicked event to ${WebviewProviderType[providerType]}:`, error)
subscriptions.delete(responseStream)
}
})
await Promise.all(promises)
}
+5 -14
View File
@@ -16,6 +16,7 @@ import { sendChatButtonClickedEvent } from "./core/controller/ui/subscribeToChat
import { ErrorService } from "./services/error/ErrorService"
import { initializeTestMode, cleanupTestMode } from "./services/test/TestMode"
import { telemetryService } from "./services/posthog/telemetry/TelemetryService"
import { sendSettingsButtonClickedEvent } from "./core/controller/ui/subscribeToSettingsButtonClicked"
import { v4 as uuidv4 } from "uuid"
import { WebviewProviderType as WebviewProviderTypeEnum } from "@shared/proto/ui"
import { WebviewProviderType } from "./shared/webview/types"
@@ -169,20 +170,10 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand("cline.settingsButtonClicked", (webview: any) => {
WebviewProvider.getAllInstances().forEach((instance) => {
const openSettings = async (instance?: WebviewProvider) => {
instance?.controller.postMessageToWebview({
type: "action",
action: "settingsButtonClicked",
})
}
const isSidebar = !webview
if (isSidebar) {
openSettings(WebviewProvider.getSidebarInstance())
} else {
WebviewProvider.getTabInstances().forEach(openSettings)
}
})
const isSidebar = !webview
const webviewType = isSidebar ? WebviewProviderTypeEnum.SIDEBAR : WebviewProviderTypeEnum.TAB
sendSettingsButtonClickedEvent(webviewType)
}),
)
+1 -1
View File
@@ -38,7 +38,7 @@ export interface ExtensionMessage {
| "fileSearchResults"
| "grpc_response" // New type for gRPC responses
text?: string
action?: "settingsButtonClicked" | "didBecomeVisible" | "accountLogoutClicked" | "focusChatInput"
action?: "didBecomeVisible" | "accountLogoutClicked" | "focusChatInput"
state?: ExtensionState
images?: string[]
files?: string[]
@@ -1,6 +1,5 @@
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from "react"
import { useEvent } from "react-use"
import { StateServiceClient, ModelsServiceClient, UiServiceClient } from "../services/grpc-client"
import { EmptyRequest } from "@shared/proto/common"
import { WebviewProviderType as WebviewProviderTypeEnum, WebviewProviderTypeRequest } from "@shared/proto/ui"
import { DEFAULT_AUTO_APPROVAL_SETTINGS } from "@shared/AutoApprovalSettings"
@@ -18,6 +17,7 @@ import {
requestyDefaultModelInfo,
} from "../../../src/shared/api"
import { McpMarketplaceCatalog, McpServer, McpViewTab } from "../../../src/shared/mcp"
import { ModelsServiceClient, StateServiceClient, UiServiceClient } from "../services/grpc-client"
import { convertTextMateToHljs } from "../utils/textMateToHljs"
import { vscode } from "../utils/vscode"
@@ -89,6 +89,9 @@ const ExtensionStateContext = createContext<ExtensionStateContextType | undefine
export const ExtensionStateContextProvider: React.FC<{
children: React.ReactNode
}> = ({ children }) => {
// Get the current webview provider type
const currentProviderType =
window.WEBVIEW_PROVIDER_TYPE === "sidebar" ? WebviewProviderTypeEnum.SIDEBAR : WebviewProviderTypeEnum.TAB
// UI view state
const [showMcp, setShowMcp] = useState(false)
const [mcpTab, setMcpTab] = useState<McpViewTab | undefined>(undefined)
@@ -191,14 +194,6 @@ export const ExtensionStateContextProvider: React.FC<{
const handleMessage = useCallback((event: MessageEvent) => {
const message: ExtensionMessage = event.data
switch (message.type) {
case "action": {
switch (message.action!) {
case "settingsButtonClicked":
navigateToSettings()
break
}
break
}
case "theme": {
if (message.text) {
setTheme(convertTextMateToHljs(JSON.parse(message.text)))
@@ -266,6 +261,7 @@ export const ExtensionStateContextProvider: React.FC<{
const historyButtonClickedSubscriptionRef = useRef<(() => void) | null>(null)
const chatButtonUnsubscribeRef = useRef<(() => void) | null>(null)
const accountButtonClickedSubscriptionRef = useRef<(() => void) | null>(null)
const settingsButtonClickedSubscriptionRef = useRef<(() => void) | null>(null)
// Subscribe to state updates and UI events using the gRPC streaming API
useEffect(() => {
@@ -395,6 +391,25 @@ export const ExtensionStateContextProvider: React.FC<{
onComplete: () => {},
})
// Set up settings button clicked subscription
settingsButtonClickedSubscriptionRef.current = UiServiceClient.subscribeToSettingsButtonClicked(
WebviewProviderTypeRequest.create({
providerType: currentProviderType,
}),
{
onResponse: () => {
// When settings button is clicked, navigate to settings
navigateToSettings()
},
onError: (error) => {
console.error("Error in settings button clicked subscription:", error)
},
onComplete: () => {
console.log("Settings button clicked subscription completed")
},
},
)
// Still send the webviewDidLaunch message for other initialization
vscode.postMessage({ type: "webviewDidLaunch" })
@@ -435,6 +450,10 @@ export const ExtensionStateContextProvider: React.FC<{
accountButtonClickedSubscriptionRef.current()
accountButtonClickedSubscriptionRef.current = null
}
if (settingsButtonClickedSubscriptionRef.current) {
settingsButtonClickedSubscriptionRef.current()
settingsButtonClickedSubscriptionRef.current = null
}
}
}, [])