This commit is contained in:
andrepimenta
2025-07-11 23:19:33 +01:00
parent cba6138828
commit 2eceda51ed
2 changed files with 130 additions and 9 deletions

View File

@@ -2335,8 +2335,6 @@ const styles = `
/* MCP Servers styles */ /* MCP Servers styles */
.mcp-servers-list { .mcp-servers-list {
max-height: 500px;
overflow-y: auto;
padding: 4px; padding: 4px;
} }
@@ -2392,6 +2390,7 @@ const styles = `
color: var(--vscode-errorForeground); color: var(--vscode-errorForeground);
border-color: var(--vscode-errorForeground); border-color: var(--vscode-errorForeground);
min-width: 80px; min-width: 80px;
justify-content: center;
} }
.server-delete-btn:hover { .server-delete-btn:hover {
@@ -2399,6 +2398,28 @@ const styles = `
border-color: var(--vscode-errorForeground); border-color: var(--vscode-errorForeground);
} }
.server-actions {
display: flex;
gap: 8px;
align-items: center;
flex-shrink: 0;
}
.server-edit-btn {
padding: 8px 16px;
font-size: 13px;
color: var(--vscode-foreground);
border-color: var(--vscode-panel-border);
min-width: 80px;
transition: all 0.2s ease;
justify-content: center;
}
.server-edit-btn:hover {
background-color: var(--vscode-list-hoverBackground);
border-color: var(--vscode-focusBorder);
}
.mcp-add-server { .mcp-add-server {
text-align: center; text-align: center;
margin-bottom: 24px; margin-bottom: 24px;
@@ -2411,8 +2432,6 @@ const styles = `
border-radius: 8px; border-radius: 8px;
padding: 24px; padding: 24px;
margin-top: 20px; margin-top: 20px;
max-height: 400px;
overflow-y: auto;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
} }

112
src/ui.ts
View File

@@ -1652,8 +1652,20 @@ const html = `<!DOCTYPE html>
document.getElementById('addServerBtn').style.display = 'block'; document.getElementById('addServerBtn').style.display = 'block';
document.getElementById('popularServers').style.display = 'block'; document.getElementById('popularServers').style.display = 'block';
document.getElementById('addServerForm').style.display = 'none'; document.getElementById('addServerForm').style.display = 'none';
// Reset editing state
editingServerName = null;
// Reset form title and button
const formTitle = document.querySelector('#addServerForm h5');
if (formTitle) formTitle.remove();
const saveBtn = document.querySelector('#addServerForm .btn:not(.outlined)');
if (saveBtn) saveBtn.textContent = 'Add Server';
// Clear form // Clear form
document.getElementById('serverName').value = ''; document.getElementById('serverName').value = '';
document.getElementById('serverName').disabled = false;
document.getElementById('serverCommand').value = ''; document.getElementById('serverCommand').value = '';
document.getElementById('serverUrl').value = ''; document.getElementById('serverUrl').value = '';
document.getElementById('serverArgs').value = ''; document.getElementById('serverArgs').value = '';
@@ -1691,16 +1703,41 @@ const html = `<!DOCTYPE html>
const type = document.getElementById('serverType').value; const type = document.getElementById('serverType').value;
if (!name) { if (!name) {
alert('Server name is required'); // Use a simple notification instead of alert which is blocked
const notification = document.createElement('div');
notification.textContent = 'Server name is required';
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
return; return;
} }
// If editing, we can use the same name; if adding, check for duplicates
if (!editingServerName) {
const serversList = document.getElementById('mcpServersList');
const existingServers = serversList.querySelectorAll('.server-name');
for (let server of existingServers) {
if (server.textContent === name) {
const notification = document.createElement('div');
notification.textContent = \`Server "\${name}" already exists\`;
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
return;
}
}
}
const serverConfig = { type }; const serverConfig = { type };
if (type === 'stdio') { if (type === 'stdio') {
const command = document.getElementById('serverCommand').value.trim(); const command = document.getElementById('serverCommand').value.trim();
if (!command) { if (!command) {
alert('Command is required for stdio servers'); const notification = document.createElement('div');
notification.textContent = 'Command is required for stdio servers';
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
return; return;
} }
serverConfig.command = command; serverConfig.command = command;
@@ -1723,7 +1760,11 @@ const html = `<!DOCTYPE html>
} else if (type === 'http' || type === 'sse') { } else if (type === 'http' || type === 'sse') {
const url = document.getElementById('serverUrl').value.trim(); const url = document.getElementById('serverUrl').value.trim();
if (!url) { if (!url) {
alert('URL is required for HTTP/SSE servers'); const notification = document.createElement('div');
notification.textContent = 'URL is required for HTTP/SSE servers';
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
return; return;
} }
serverConfig.url = url; serverConfig.url = url;
@@ -1757,13 +1798,71 @@ const html = `<!DOCTYPE html>
}); });
} }
let editingServerName = null;
function editMCPServer(name, config) {
editingServerName = name;
// Hide add button and popular servers
document.getElementById('addServerBtn').style.display = 'none';
document.getElementById('popularServers').style.display = 'none';
// Show form
document.getElementById('addServerForm').style.display = 'block';
// Update form title and button
const formTitle = document.querySelector('#addServerForm h5') ||
document.querySelector('#addServerForm').insertAdjacentHTML('afterbegin', '<h5>Edit MCP Server</h5>') ||
document.querySelector('#addServerForm h5');
if (!document.querySelector('#addServerForm h5')) {
document.getElementById('addServerForm').insertAdjacentHTML('afterbegin', '<h5 style="margin: 0 0 20px 0; font-size: 14px; font-weight: 600;">Edit MCP Server</h5>');
} else {
document.querySelector('#addServerForm h5').textContent = 'Edit MCP Server';
}
// Update save button text
const saveBtn = document.querySelector('#addServerForm .btn:not(.outlined)');
if (saveBtn) saveBtn.textContent = 'Update Server';
// Populate form with existing values
document.getElementById('serverName').value = name;
document.getElementById('serverName').disabled = true; // Don't allow name changes when editing
document.getElementById('serverType').value = config.type || 'stdio';
if (config.command) {
document.getElementById('serverCommand').value = config.command;
}
if (config.url) {
document.getElementById('serverUrl').value = config.url;
}
if (config.args && Array.isArray(config.args)) {
document.getElementById('serverArgs').value = config.args.join('\\n');
}
if (config.env) {
const envLines = Object.entries(config.env).map(([key, value]) => \`\${key}=\${value}\`);
document.getElementById('serverEnv').value = envLines.join('\\n');
}
if (config.headers) {
const headerLines = Object.entries(config.headers).map(([key, value]) => \`\${key}=\${value}\`);
document.getElementById('serverHeaders').value = headerLines.join('\\n');
}
// Update form field visibility
updateServerForm();
}
function addPopularServer(name, config) { function addPopularServer(name, config) {
// Check if server already exists // Check if server already exists
const serversList = document.getElementById('mcpServersList'); const serversList = document.getElementById('mcpServersList');
const existingServers = serversList.querySelectorAll('.server-name'); const existingServers = serversList.querySelectorAll('.server-name');
for (let server of existingServers) { for (let server of existingServers) {
if (server.textContent === name) { if (server.textContent === name) {
alert(\`Server "\${name}" already exists.\`); const notification = document.createElement('div');
notification.textContent = \`Server "\${name}" already exists\`;
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
return; return;
} }
} }
@@ -1815,7 +1914,10 @@ const html = `<!DOCTYPE html>
<div class="server-type">\${serverType.toUpperCase()}</div> <div class="server-type">\${serverType.toUpperCase()}</div>
<div class="server-config">\${configDisplay}</div> <div class="server-config">\${configDisplay}</div>
</div> </div>
<button class="btn outlined server-delete-btn" onclick="deleteMCPServer('\${name}')">Delete</button> <div class="server-actions">
<button class="btn outlined server-edit-btn" onclick="editMCPServer('\${name}', \${JSON.stringify(config).replace(/"/g, '&quot;')})">Edit</button>
<button class="btn outlined server-delete-btn" onclick="deleteMCPServer('\${name}')">Delete</button>
</div>
\`; \`;
serversList.appendChild(serverItem); serversList.appendChild(serverItem);