实现 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",
|
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
|
||||||
"title": "展示 OpenMCP",
|
"title": "连接",
|
||||||
"category": "openmcp",
|
"category": "openmcp",
|
||||||
"icon": {
|
"icon": {
|
||||||
"light": "./icons/light/protocol.svg",
|
"light": "./icons/light/protocol.svg",
|
||||||
@ -58,8 +58,11 @@
|
|||||||
"view/item/context": [
|
"view/item/context": [
|
||||||
{
|
{
|
||||||
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
|
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
|
||||||
"group": "navigation",
|
"group": "inline@1",
|
||||||
"when": "view == openmcp.sidebar-view.workspace-connection"
|
"when": "view == openmcp.sidebar-view.workspace-connection",
|
||||||
|
"args": {
|
||||||
|
"view": "${viewItem}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -77,7 +80,7 @@
|
|||||||
{
|
{
|
||||||
"id": "openmcp.sidebar-view.workspace-connection",
|
"id": "openmcp.sidebar-view.workspace-connection",
|
||||||
"icon": "./icons/protocol.svg",
|
"icon": "./icons/protocol.svg",
|
||||||
"name": "MCP 连接",
|
"name": "MCP 连接 (工作区)",
|
||||||
"type": "tree"
|
"type": "tree"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ import * as fspath from 'path';
|
|||||||
|
|
||||||
import * as OpenMCPService from '../resources/service';
|
import * as OpenMCPService from '../resources/service';
|
||||||
import { getLaunchCWD, revealOpenMcpWebviewPanel } from './webview';
|
import { getLaunchCWD, revealOpenMcpWebviewPanel } from './webview';
|
||||||
import { registerSidebar } from './sidebar';
|
import { ConnectionViewItem, registerSidebar } from './sidebar';
|
||||||
import { getWorkspaceConnectionConfigItemByPath, ISSEConnectionItem, IStdioConnectionItem } from './global';
|
import { getWorkspaceConnectionConfigItemByPath, ISSEConnectionItem, IStdioConnectionItem } from './global';
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
@ -18,7 +18,8 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
registerSidebar(context);
|
registerSidebar(context);
|
||||||
|
|
||||||
context.subscriptions.push(
|
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);
|
revealOpenMcpWebviewPanel(context, item.name, item);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -82,10 +82,10 @@ export function getWorkspaceConnectionConfig() {
|
|||||||
const workspacePath = getWorkspacePath();
|
const workspacePath = getWorkspacePath();
|
||||||
for (const item of connection.items) {
|
for (const item of connection.items) {
|
||||||
if (item.filePath && item.filePath.startsWith('{workspace}')) {
|
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}')) {
|
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();
|
const workspacePath = getWorkspacePath();
|
||||||
for (const item of connectionConfig.items) {
|
for (const item of connectionConfig.items) {
|
||||||
if (item.filePath && item.filePath.startsWith(workspacePath)) {
|
if (item.filePath && item.filePath.replace(/\\/g, '/').startsWith(workspacePath)) {
|
||||||
item.filePath = item.filePath.replace(workspacePath, '{workspace}').replace('\\', '/');
|
item.filePath = item.filePath.replace(workspacePath, '{workspace}').replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
if (item.type ==='stdio' && item.cwd && item.cwd.startsWith(workspacePath)) {
|
if (item.type ==='stdio' && item.cwd && item.cwd.replace(/\\/g, '/').startsWith(workspacePath)) {
|
||||||
item.cwd = item.cwd.replace(workspacePath, '{workspace}').replace('\\', '/');
|
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 {
|
interface ClientStdioConnectionItem {
|
||||||
@ -152,9 +152,9 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
|||||||
name: data.clientName,
|
name: data.clientName,
|
||||||
command: data.command,
|
command: data.command,
|
||||||
args: data.args,
|
args: data.args,
|
||||||
cwd: data.cwd.replace('\\', '/'),
|
cwd: data.cwd.replace(/\\/g, '/'),
|
||||||
env: data.env,
|
env: data.env,
|
||||||
filePath: absPath.replace('\\', '/')
|
filePath: absPath.replace(/\\/g, '/')
|
||||||
};
|
};
|
||||||
|
|
||||||
// 插入到第一个
|
// 插入到第一个
|
||||||
@ -162,7 +162,7 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
|||||||
const workspacePath = getWorkspacePath();
|
const workspacePath = getWorkspacePath();
|
||||||
saveWorkspaceConnectionConfig(workspacePath);
|
saveWorkspaceConnectionConfig(workspacePath);
|
||||||
vscode.commands.executeCommand('openmcp.sidebar.workspace-connection.refresh');
|
vscode.commands.executeCommand('openmcp.sidebar.workspace-connection.refresh');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -171,9 +171,9 @@ export function updateWorkspaceConnectionConfig(absPath: string, data: ClientStd
|
|||||||
function normaliseConnectionFilePath(item: IStdioConnectionItem | ISSEConnectionItem, workspace: string) {
|
function normaliseConnectionFilePath(item: IStdioConnectionItem | ISSEConnectionItem, workspace: string) {
|
||||||
if (item.filePath) {
|
if (item.filePath) {
|
||||||
if (item.filePath.startsWith('{workspace}')) {
|
if (item.filePath.startsWith('{workspace}')) {
|
||||||
return item.filePath.replace('{workspace}', workspace).replace('\\', '/');
|
return item.filePath.replace('{workspace}', workspace).replace(/\\/g, '/');
|
||||||
} else {
|
} else {
|
||||||
return item.filePath.replace('\\', '/');
|
return item.filePath.replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ function normaliseConnectionFilePath(item: IStdioConnectionItem | ISSEConnection
|
|||||||
|
|
||||||
export function getWorkspacePath() {
|
export function getWorkspacePath() {
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
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 workspacePath = getWorkspacePath();
|
||||||
const workspaceConnectionConfig = getWorkspaceConnectionConfig();
|
const workspaceConnectionConfig = getWorkspaceConnectionConfig();
|
||||||
|
|
||||||
const normaliseAbsPath = absPath.replace('\\', '/');
|
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
||||||
for (const item of workspaceConnectionConfig.items) {
|
for (const item of workspaceConnectionConfig.items) {
|
||||||
const filePath = normaliseConnectionFilePath(item, workspacePath);
|
const filePath = normaliseConnectionFilePath(item, workspacePath);
|
||||||
if (filePath === normaliseAbsPath) {
|
if (filePath === normaliseAbsPath) {
|
||||||
|
@ -1,29 +1,39 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { getConnectionConfig, getWorkspaceConnectionConfig } from './global';
|
import { getConnectionConfig, getWorkspaceConnectionConfig, ISSEConnectionItem, IStdioConnectionItem } from './global';
|
||||||
|
|
||||||
class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<SidebarItem> {
|
class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<ConnectionViewItem> {
|
||||||
private _onDidChangeTreeData: vscode.EventEmitter<SidebarItem | undefined | null | void> = new vscode.EventEmitter<SidebarItem | undefined | null | void>();
|
private _onDidChangeTreeData: vscode.EventEmitter<ConnectionViewItem | undefined | null | void> = new vscode.EventEmitter<ConnectionViewItem | undefined | null | void>();
|
||||||
readonly onDidChangeTreeData: vscode.Event<SidebarItem | undefined | null | void> = this._onDidChangeTreeData.event;
|
readonly onDidChangeTreeData: vscode.Event<ConnectionViewItem | undefined | null | void> = this._onDidChangeTreeData.event;
|
||||||
|
|
||||||
constructor(private context: vscode.ExtensionContext) {
|
constructor(private context: vscode.ExtensionContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 实现 TreeDataProvider 接口
|
// 实现 TreeDataProvider 接口
|
||||||
getTreeItem(element: SidebarItem): vscode.TreeItem {
|
getTreeItem(element: ConnectionViewItem): vscode.TreeItem {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildren(element?: SidebarItem): Thenable<SidebarItem[]> {
|
getChildren(element?: ConnectionViewItem): Thenable<ConnectionViewItem[]> {
|
||||||
// TODO: 读取 configDir 下的所有文件,作为子节点
|
// TODO: 读取 configDir 下的所有文件,作为子节点
|
||||||
const connection = getWorkspaceConnectionConfig();
|
const connection = getWorkspaceConnectionConfig();
|
||||||
const sidebarItems = connection.items.map((item, index) => {
|
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);
|
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 方法
|
// 添加 refresh 方法
|
||||||
public refresh(): void {
|
public refresh(): void {
|
||||||
this._onDidChangeTreeData.fire();
|
this._onDidChangeTreeData.fire();
|
||||||
@ -105,4 +115,16 @@ class SidebarItem extends vscode.TreeItem {
|
|||||||
this.command = command;
|
this.command = command;
|
||||||
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
|
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