实现 vscode 内 sidebar 的实现
This commit is contained in:
parent
5bac8f8726
commit
4473421708
11
package.json
11
package.json
@ -34,7 +34,7 @@
|
||||
},
|
||||
{
|
||||
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
|
||||
"title": "展示 OpenMCP",
|
||||
"title": "连接",
|
||||
"category": "openmcp",
|
||||
"icon": {
|
||||
"light": "./icons/light/protocol.svg",
|
||||
@ -58,8 +58,11 @@
|
||||
"view/item/context": [
|
||||
{
|
||||
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
|
||||
"group": "navigation",
|
||||
"when": "view == openmcp.sidebar-view.workspace-connection"
|
||||
"group": "inline@1",
|
||||
"when": "view == openmcp.sidebar-view.workspace-connection",
|
||||
"args": {
|
||||
"view": "${viewItem}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -77,7 +80,7 @@
|
||||
{
|
||||
"id": "openmcp.sidebar-view.workspace-connection",
|
||||
"icon": "./icons/protocol.svg",
|
||||
"name": "MCP 连接",
|
||||
"name": "MCP 连接 (工作区)",
|
||||
"type": "tree"
|
||||
},
|
||||
{
|
||||
|
@ -3,7 +3,7 @@ import * as fspath from 'path';
|
||||
|
||||
import * as OpenMCPService from '../resources/service';
|
||||
import { getLaunchCWD, revealOpenMcpWebviewPanel } from './webview';
|
||||
import { registerSidebar } from './sidebar';
|
||||
import { ConnectionViewItem, registerSidebar } from './sidebar';
|
||||
import { getWorkspaceConnectionConfigItemByPath, ISSEConnectionItem, IStdioConnectionItem } from './global';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
@ -18,7 +18,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
registerSidebar(context);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.revealWebviewPanel', (item: IStdioConnectionItem | ISSEConnectionItem) => {
|
||||
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.revealWebviewPanel', (view: ConnectionViewItem) => {
|
||||
const item = view.item;
|
||||
revealOpenMcpWebviewPanel(context, item.name, item);
|
||||
})
|
||||
);
|
||||
|
@ -82,10 +82,10 @@ export function getWorkspaceConnectionConfig() {
|
||||
const workspacePath = getWorkspacePath();
|
||||
for (const item of connection.items) {
|
||||
if (item.filePath && item.filePath.startsWith('{workspace}')) {
|
||||
item.filePath = item.filePath.replace('{workspace}', workspacePath).replace('\\', '/');
|
||||
item.filePath = item.filePath.replace('{workspace}', workspacePath).replace(/\\/g, '/');
|
||||
}
|
||||
if (item.type === 'stdio' && item.cwd && item.cwd.startsWith('{workspace}')) {
|
||||
item.cwd = item.cwd.replace('{workspace}', workspacePath).replace('\\', '/');
|
||||
item.cwd = item.cwd.replace('{workspace}', workspacePath).replace(/\\/g, '/');
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,14 +106,14 @@ export function saveWorkspaceConnectionConfig(workspace: string) {
|
||||
|
||||
const workspacePath = getWorkspacePath();
|
||||
for (const item of connectionConfig.items) {
|
||||
if (item.filePath && item.filePath.startsWith(workspacePath)) {
|
||||
item.filePath = item.filePath.replace(workspacePath, '{workspace}').replace('\\', '/');
|
||||
if (item.filePath && item.filePath.replace(/\\/g, '/').startsWith(workspacePath)) {
|
||||
item.filePath = item.filePath.replace(workspacePath, '{workspace}').replace(/\\/g, '/');
|
||||
}
|
||||
if (item.type ==='stdio' && item.cwd && item.cwd.startsWith(workspacePath)) {
|
||||
item.cwd = item.cwd.replace(workspacePath, '{workspace}').replace('\\', '/');
|
||||
if (item.type ==='stdio' && item.cwd && item.cwd.replace(/\\/g, '/').startsWith(workspacePath)) {
|
||||
item.cwd = item.cwd.replace(workspacePath, '{workspace}').replace(/\\/g, '/');
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(connectionConfigPath, JSON.stringify(connectionConfig), 'utf-8');
|
||||
fs.writeFileSync(connectionConfigPath, JSON.stringify(connectionConfig, null, 2), 'utf-8');
|
||||
}
|
||||
|
||||
interface ClientStdioConnectionItem {
|
||||
@ -152,9 +152,9 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
||||
name: data.clientName,
|
||||
command: data.command,
|
||||
args: data.args,
|
||||
cwd: data.cwd.replace('\\', '/'),
|
||||
cwd: data.cwd.replace(/\\/g, '/'),
|
||||
env: data.env,
|
||||
filePath: absPath.replace('\\', '/')
|
||||
filePath: absPath.replace(/\\/g, '/')
|
||||
};
|
||||
|
||||
// 插入到第一个
|
||||
@ -162,7 +162,7 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
||||
const workspacePath = getWorkspacePath();
|
||||
saveWorkspaceConnectionConfig(workspacePath);
|
||||
vscode.commands.executeCommand('openmcp.sidebar.workspace-connection.refresh');
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -171,9 +171,9 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
||||
function normaliseConnectionFilePath(item: IStdioConnectionItem | ISSEConnectionItem, workspace: string) {
|
||||
if (item.filePath) {
|
||||
if (item.filePath.startsWith('{workspace}')) {
|
||||
return item.filePath.replace('{workspace}', workspace).replace('\\', '/');
|
||||
return item.filePath.replace('{workspace}', workspace).replace(/\\/g, '/');
|
||||
} else {
|
||||
return item.filePath.replace('\\', '/');
|
||||
return item.filePath.replace(/\\/g, '/');
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ function normaliseConnectionFilePath(item: IStdioConnectionItem | ISSEConnection
|
||||
|
||||
export function getWorkspacePath() {
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
return (workspaceFolder?.uri.fsPath || '').replace('\\', '/');
|
||||
return (workspaceFolder?.uri.fsPath || '').replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,7 +193,7 @@ export function getWorkspaceConnectionConfigItemByPath(absPath: string) {
|
||||
const workspacePath = getWorkspacePath();
|
||||
const workspaceConnectionConfig = getWorkspaceConnectionConfig();
|
||||
|
||||
const normaliseAbsPath = absPath.replace('\\', '/');
|
||||
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
||||
for (const item of workspaceConnectionConfig.items) {
|
||||
const filePath = normaliseConnectionFilePath(item, workspacePath);
|
||||
if (filePath === normaliseAbsPath) {
|
||||
|
@ -1,29 +1,39 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { getConnectionConfig, getWorkspaceConnectionConfig } from './global';
|
||||
import { getConnectionConfig, getWorkspaceConnectionConfig, ISSEConnectionItem, IStdioConnectionItem } from './global';
|
||||
|
||||
class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<SidebarItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<SidebarItem | undefined | null | void> = new vscode.EventEmitter<SidebarItem | undefined | null | void>();
|
||||
readonly onDidChangeTreeData: vscode.Event<SidebarItem | undefined | null | void> = this._onDidChangeTreeData.event;
|
||||
class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<ConnectionViewItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<ConnectionViewItem | undefined | null | void> = new vscode.EventEmitter<ConnectionViewItem | undefined | null | void>();
|
||||
readonly onDidChangeTreeData: vscode.Event<ConnectionViewItem | undefined | null | void> = this._onDidChangeTreeData.event;
|
||||
|
||||
constructor(private context: vscode.ExtensionContext) {
|
||||
}
|
||||
|
||||
// 实现 TreeDataProvider 接口
|
||||
getTreeItem(element: SidebarItem): vscode.TreeItem {
|
||||
getTreeItem(element: ConnectionViewItem): vscode.TreeItem {
|
||||
return element;
|
||||
}
|
||||
|
||||
getChildren(element?: SidebarItem): Thenable<SidebarItem[]> {
|
||||
getChildren(element?: ConnectionViewItem): Thenable<ConnectionViewItem[]> {
|
||||
// TODO: 读取 configDir 下的所有文件,作为子节点
|
||||
const connection = getWorkspaceConnectionConfig();
|
||||
const sidebarItems = connection.items.map((item, index) => {
|
||||
return new SidebarItem(item.name, vscode.TreeItemCollapsibleState.None);
|
||||
// 连接的名字
|
||||
const itemName = this.displayName(item);
|
||||
return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server');
|
||||
})
|
||||
|
||||
// 返回子节点
|
||||
return Promise.resolve(sidebarItems);
|
||||
}
|
||||
|
||||
public displayName(item: IStdioConnectionItem | ISSEConnectionItem) {
|
||||
if (item.filePath) {
|
||||
const filename = item.filePath.split('/').pop();
|
||||
return `${filename} (${item.type})`;
|
||||
}
|
||||
return item.name;
|
||||
}
|
||||
|
||||
// 添加 refresh 方法
|
||||
public refresh(): void {
|
||||
this._onDidChangeTreeData.fire();
|
||||
@ -105,4 +115,16 @@ class SidebarItem extends vscode.TreeItem {
|
||||
this.command = command;
|
||||
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
|
||||
}
|
||||
}
|
||||
|
||||
export class ConnectionViewItem extends vscode.TreeItem {
|
||||
constructor(
|
||||
public readonly label: string,
|
||||
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
|
||||
public readonly item: IStdioConnectionItem | ISSEConnectionItem,
|
||||
public readonly icon?: string
|
||||
) {
|
||||
super(label, collapsibleState);
|
||||
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user