mirror of
https://github.com/cline/cline.git
synced 2026-09-19 02:05:44 +08:00
fix webview
This commit is contained in:
@@ -1672,6 +1672,7 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont
|
||||
planActSeparateModelsSetting,
|
||||
globalClineRulesToggles,
|
||||
shellIntegrationTimeout,
|
||||
showWelcome,
|
||||
} = await getAllExtensionState(this.context)
|
||||
|
||||
const localClineRulesToggles =
|
||||
@@ -1704,7 +1705,7 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont
|
||||
mcpMarketplaceEnabled,
|
||||
telemetrySetting,
|
||||
planActSeparateModelsSetting,
|
||||
showWelcome: false,
|
||||
showWelcome,
|
||||
vscMachineId: vscode.env.machineId,
|
||||
globalClineRulesToggles: globalClineRulesToggles || {},
|
||||
localClineRulesToggles: localClineRulesToggles || {},
|
||||
|
||||
@@ -81,5 +81,6 @@ export type GlobalStateKey =
|
||||
| "favoritedModelIds"
|
||||
| "requestTimeoutMs"
|
||||
| "shellIntegrationTimeout"
|
||||
| "showWelcome"
|
||||
|
||||
export type LocalStateKey = "localClineRulesToggles"
|
||||
|
||||
@@ -131,6 +131,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
globalClineRulesToggles,
|
||||
requestTimeoutMs,
|
||||
shellIntegrationTimeout,
|
||||
showWelcome,
|
||||
] = await Promise.all([
|
||||
getGlobalState(context, "apiProvider") as Promise<ApiProvider | undefined>,
|
||||
getGlobalState(context, "apiModelId") as Promise<string | undefined>,
|
||||
@@ -210,6 +211,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
getGlobalState(context, "globalClineRulesToggles") as Promise<ClineRulesToggles | undefined>,
|
||||
getGlobalState(context, "requestTimeoutMs") as Promise<number | undefined>,
|
||||
getGlobalState(context, "shellIntegrationTimeout") as Promise<number | undefined>,
|
||||
getGlobalState(context, "showWelcome") as Promise<boolean | undefined>,
|
||||
])
|
||||
|
||||
let apiProvider: ApiProvider
|
||||
@@ -334,6 +336,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
telemetrySetting: telemetrySetting || "unset",
|
||||
planActSeparateModelsSetting,
|
||||
shellIntegrationTimeout: shellIntegrationTimeout || 4000,
|
||||
showWelcome,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { findLast } from "@shared/array"
|
||||
import { readFile } from "fs/promises"
|
||||
import path from "node:path"
|
||||
import { WebviewType } from "@shared/WebviewMessage"
|
||||
import { setTimeout as setTimeoutPromise } from "node:timers/promises"
|
||||
/*
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
|
||||
https://github.com/KumarVariable/vscode-extension-sidebar-html/blob/master/src/customSidebarViewProvider.ts
|
||||
@@ -87,12 +88,31 @@ export class WebviewProvider implements vscode.WebviewViewProvider {
|
||||
// WebviewView and WebviewPanel have all the same properties except for this visibility listener
|
||||
// panel
|
||||
webviewView.onDidChangeViewState(
|
||||
() => {
|
||||
async () => {
|
||||
if (this.view?.visible) {
|
||||
// Check if showWelcome flag is set in global state
|
||||
const showWelcome = await this.controller.context.globalState.get<boolean>("showWelcome")
|
||||
|
||||
// Send didBecomeVisible action
|
||||
this.controller.postMessageToWebview({
|
||||
type: "action",
|
||||
action: "didBecomeVisible",
|
||||
})
|
||||
|
||||
// If showWelcome flag is set, send showWelcome message and clear the flag
|
||||
// We're now sending it to all webviews to ensure it's displayed
|
||||
if (showWelcome) {
|
||||
console.log(`Sending showWelcome message to ${this.webviewType} webview`)
|
||||
this.controller.postMessageToWebview({
|
||||
type: "showWelcome",
|
||||
})
|
||||
|
||||
// Add a delay before clearing the flag to ensure the webview has time to process it
|
||||
await setTimeoutPromise(1000)
|
||||
|
||||
// Clear the flag after sending the message
|
||||
await this.controller.context.globalState.update("showWelcome", undefined)
|
||||
}
|
||||
}
|
||||
},
|
||||
null,
|
||||
@@ -101,12 +121,30 @@ export class WebviewProvider implements vscode.WebviewViewProvider {
|
||||
} else if ("onDidChangeVisibility" in webviewView) {
|
||||
// sidebar
|
||||
webviewView.onDidChangeVisibility(
|
||||
() => {
|
||||
async () => {
|
||||
if (this.view?.visible) {
|
||||
// Check if showWelcome flag is set in global state
|
||||
const showWelcome = await this.controller.context.globalState.get<boolean>("showWelcome")
|
||||
|
||||
// Send didBecomeVisible action
|
||||
this.controller.postMessageToWebview({
|
||||
type: "action",
|
||||
action: "didBecomeVisible",
|
||||
})
|
||||
|
||||
// If showWelcome flag is set, send showWelcome message and clear the flag
|
||||
if (showWelcome) {
|
||||
console.log(`Sending showWelcome message to ${this.webviewType} webview`)
|
||||
this.controller.postMessageToWebview({
|
||||
type: "showWelcome",
|
||||
})
|
||||
|
||||
// Add a delay before clearing the flag to ensure the webview has time to process it
|
||||
await setTimeoutPromise(1000)
|
||||
|
||||
// Clear the flag after sending the message
|
||||
await this.controller.context.globalState.update("showWelcome", undefined)
|
||||
}
|
||||
}
|
||||
},
|
||||
null,
|
||||
@@ -222,6 +260,7 @@ export class WebviewProvider implements vscode.WebviewViewProvider {
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="webview-type" content="${this.webviewType}">
|
||||
<link rel="stylesheet" type="text/css" href="${stylesUri}">
|
||||
<link href="${codiconsUri}" rel="stylesheet" />
|
||||
<link href="${katexCssUri}" rel="stylesheet" />
|
||||
|
||||
+30
-12
@@ -82,37 +82,46 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
const openClineInNewTab = async (): Promise<WebviewProvider> => {
|
||||
const openClineInNewTab = async (isWelcome = false): Promise<WebviewProvider> => {
|
||||
Logger.log("Opening Cline in new tab")
|
||||
// (this example uses webviewProvider activation event which is necessary to deserialize cached webview, but since we use retainContextWhenHidden, we don't need to use that event)
|
||||
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
|
||||
const tabWebview = new WebviewProvider(context, outputChannel, "tab")
|
||||
//const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined
|
||||
const lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))
|
||||
let targetCol: vscode.ViewColumn
|
||||
|
||||
// Check if there are any visible text editors, otherwise open a new group to the right
|
||||
const hasVisibleEditors = vscode.window.visibleTextEditors.length > 0
|
||||
if (!hasVisibleEditors) {
|
||||
await vscode.commands.executeCommand("workbench.action.newGroupRight")
|
||||
if (!isWelcome) {
|
||||
//const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined
|
||||
const lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))
|
||||
|
||||
// Check if there are any visible text editors, otherwise open a new group to the right
|
||||
const hasVisibleEditors = vscode.window.visibleTextEditors.length > 0
|
||||
if (!hasVisibleEditors) {
|
||||
await vscode.commands.executeCommand("workbench.action.newGroupRight")
|
||||
}
|
||||
targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Two
|
||||
} else {
|
||||
targetCol = vscode.ViewColumn.One
|
||||
}
|
||||
const targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Two
|
||||
|
||||
const panel = vscode.window.createWebviewPanel(WebviewProvider.tabPanelId, "Cline", targetCol, {
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [context.extensionUri],
|
||||
})
|
||||
// TODO: use better svg icon with light and dark variants (see https://stackoverflow.com/questions/58365687/vscode-extension-iconpath)
|
||||
|
||||
panel.iconPath = {
|
||||
light: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "robot_panel_light.png"),
|
||||
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "robot_panel_dark.png"),
|
||||
}
|
||||
tabWebview.resolveWebviewView(panel)
|
||||
|
||||
await tabWebview.resolveWebviewView(panel)
|
||||
|
||||
// Lock the editor group so clicking on files doesn't open them over the panel
|
||||
await setTimeoutPromise(100)
|
||||
await vscode.commands.executeCommand("workbench.action.lockEditorGroup")
|
||||
|
||||
if (isWelcome) {
|
||||
panel.reveal(targetCol)
|
||||
}
|
||||
return tabWebview
|
||||
}
|
||||
|
||||
@@ -432,8 +441,17 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const previous = context.globalState.get<string>(VERSION_KEY)
|
||||
|
||||
if (!previous) {
|
||||
const tab = await openClineInNewTab()
|
||||
console.log("First time installation detected, setting showWelcome flag")
|
||||
// Set the showWelcome flag to true in global state
|
||||
await context.globalState.update("showWelcome", true)
|
||||
|
||||
// Open a single tab with the welcome screen
|
||||
const tab = await openClineInNewTab(true)
|
||||
console.log("Tab opened for welcome screen")
|
||||
|
||||
// Send the showWelcome message directly to the webview
|
||||
await tab.controller.postMessageToWebview({ type: "showWelcome" })
|
||||
console.log("Sent showWelcome message directly to webview")
|
||||
|
||||
// persist for the next activation
|
||||
await context.globalState.update(VERSION_KEY, current)
|
||||
|
||||
@@ -144,6 +144,7 @@ export interface ExtensionState {
|
||||
localClineRulesToggles: ClineRulesToggles
|
||||
localCursorRulesToggles: ClineRulesToggles
|
||||
localWindsurfRulesToggles: ClineRulesToggles
|
||||
showWelcome?: boolean
|
||||
}
|
||||
|
||||
export interface ClineMessage {
|
||||
|
||||
+17
-2
@@ -14,12 +14,21 @@ import { McpViewTab } from "@shared/mcp"
|
||||
import WelcomeWrapper from "./components/welcome/WelcomeWrapper"
|
||||
|
||||
const AppContent = () => {
|
||||
const { didHydrateState, shouldShowAnnouncement, showMcp, mcpTab, showWelcome } = useExtensionState()
|
||||
const { didHydrateState, shouldShowAnnouncement, showMcp, mcpTab } = useExtensionState()
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const hideSettings = useCallback(() => setShowSettings(false), [])
|
||||
const [showHistory, setShowHistory] = useState(false)
|
||||
const [showAccount, setShowAccount] = useState(false)
|
||||
const [showAnnouncement, setShowAnnouncement] = useState(false)
|
||||
// Use local state for welcome view, initialized from extension state
|
||||
const [showWelcomeLocal, setShowWelcomeLocal] = useState(true)
|
||||
const { setShowWelcome } = useExtensionState()
|
||||
|
||||
// Sync local state with extension state
|
||||
useEffect(() => {
|
||||
console.log("Setting showWelcome in extension state to true")
|
||||
setShowWelcome(true)
|
||||
}, [setShowWelcome])
|
||||
|
||||
const { setShowMcp, setMcpTab } = useExtensionState()
|
||||
|
||||
@@ -31,7 +40,12 @@ const AppContent = () => {
|
||||
const handleMessage = useCallback(
|
||||
(e: MessageEvent) => {
|
||||
const message: ExtensionMessage = e.data
|
||||
console.log("Received message in App.tsx:", message)
|
||||
switch (message.type) {
|
||||
case "showWelcome":
|
||||
console.log("Received showWelcome message in App.tsx")
|
||||
setShowWelcomeLocal(true)
|
||||
break
|
||||
case "action":
|
||||
switch (message.action!) {
|
||||
case "settingsButtonClicked":
|
||||
@@ -66,6 +80,7 @@ const AppContent = () => {
|
||||
setShowHistory(false)
|
||||
closeMcpView()
|
||||
setShowAccount(false)
|
||||
setShowWelcomeLocal(false) // Hide welcome view when chat button is clicked
|
||||
break
|
||||
}
|
||||
break
|
||||
@@ -98,7 +113,7 @@ const AppContent = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{showWelcome ? (
|
||||
{showWelcomeLocal ? (
|
||||
<WelcomeWrapper />
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -118,11 +118,6 @@ const WelcomeTabView = memo(({ onToggleView, showApiOptions, setShowApiOptions }
|
||||
<button className="primary-button" onClick={handleLogin}>
|
||||
Let's Create your Account!
|
||||
</button>
|
||||
{showApiOptions !== undefined && setShowApiOptions !== undefined && !showApiOptions && (
|
||||
<button className="secondary-button" onClick={() => setShowApiOptions(true)}>
|
||||
Use your own API key
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{showApiOptions !== undefined && <ApiOptionsSection showApiOptions={showApiOptions} />}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user