imcp 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/serve.js +2 -1
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +25 -2
- package/dist/core/installers/clients/BaseClientInstaller.js +121 -0
- package/dist/core/installers/clients/ClineInstaller.d.ts +1 -6
- package/dist/core/installers/clients/ClineInstaller.js +1 -94
- package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +1 -6
- package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -94
- package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +1 -5
- package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -94
- package/dist/core/loaders/ConfigurationLoader.d.ts +4 -1
- package/dist/core/loaders/ConfigurationLoader.js +24 -3
- package/dist/core/loaders/ConfigurationProvider.d.ts +4 -1
- package/dist/core/loaders/ConfigurationProvider.js +13 -4
- package/dist/core/loaders/ServerSchemaLoader.d.ts +15 -4
- package/dist/core/loaders/ServerSchemaLoader.js +86 -20
- package/dist/core/loaders/ServerSchemaProvider.d.ts +2 -5
- package/dist/core/loaders/ServerSchemaProvider.js +32 -62
- package/dist/core/metadatas/types.d.ts +3 -2
- package/dist/core/onboard/FeedOnboardService.d.ts +14 -7
- package/dist/core/onboard/FeedOnboardService.js +214 -129
- package/dist/core/onboard/OnboardProcessor.d.ts +7 -1
- package/dist/core/onboard/OnboardProcessor.js +52 -8
- package/dist/core/onboard/OnboardStatus.d.ts +6 -1
- package/dist/core/onboard/OnboardStatusManager.d.ts +70 -24
- package/dist/core/onboard/OnboardStatusManager.js +230 -46
- package/dist/core/validators/FeedValidator.d.ts +7 -2
- package/dist/core/validators/FeedValidator.js +61 -7
- package/dist/core/validators/StdioServerValidator.js +84 -32
- package/dist/services/MCPManager.d.ts +2 -1
- package/dist/services/MCPManager.js +5 -1
- package/dist/services/ServerService.js +2 -2
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +10 -0
- package/dist/web/public/js/modal/installation.js +1 -1
- package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +41 -9
- package/dist/web/public/js/onboard/formProcessor.js +200 -34
- package/dist/web/public/js/onboard/index.js +2 -2
- package/dist/web/public/js/onboard/publishHandler.js +30 -22
- package/dist/web/public/js/onboard/templates.js +34 -40
- package/dist/web/public/js/onboard/uiHandlers.js +175 -84
- package/dist/web/public/js/onboard/validationHandlers.js +147 -64
- package/dist/web/public/js/serverCategoryDetails.js +19 -4
- package/dist/web/public/js/serverCategoryList.js +13 -1
- package/dist/web/public/onboard.html +1 -1
- package/dist/web/server.js +19 -6
- package/package.json +1 -1
|
@@ -43,13 +43,62 @@ let pollingIntervalId = null;
|
|
|
43
43
|
* @param {HTMLElement} contentElement - The HTML element to update.
|
|
44
44
|
*/
|
|
45
45
|
export function updateOperationDisplay(data, contentElement) { // Renamed from updateValidationDisplay
|
|
46
|
-
const { status, message, validationStatus, prInfo, errorMessage: operationErrorMessage, operationType } = data;
|
|
47
|
-
|
|
46
|
+
const { status, message, validationStatus, prInfo, errorMessage: operationErrorMessage, operationType, steps } = data; // Added steps
|
|
47
|
+
const upperStatus = typeof status === 'string' ? status.toUpperCase() : ''; // Overall status
|
|
48
|
+
const isInProgressOverall = upperStatus === 'PENDING' || upperStatus === 'VALIDATING' || upperStatus === 'PRCREATING' || upperStatus === 'IN_PROGRESS' || upperStatus === 'PUBLISHING';
|
|
49
|
+
|
|
50
|
+
let htmlContent = `<p><strong>Overall Status:</strong> <span class="${upperStatus === 'COMPLETED' || upperStatus === 'SUCCEEDED' ? 'text-green-600' : (upperStatus === 'FAILED' ? 'text-red-600' : 'text-yellow-600')}">${status} ${isInProgressOverall ? "<i class='bx bx-loader-alt bx-spin ml-2'></i>" : ""}</span></p>`;
|
|
48
51
|
if (operationType) htmlContent += `<p><strong>Operation Type:</strong> ${operationType}</p>`;
|
|
52
|
+
// Show message if provided, especially useful for direct success/failure from API.
|
|
49
53
|
if (message) htmlContent += `<p><strong>Message:</strong> ${message}</p>`;
|
|
50
|
-
if (operationErrorMessage) htmlContent += `<p class="text-red-500"><strong>Error:</strong> ${operationErrorMessage}</p>`;
|
|
54
|
+
if (operationErrorMessage) htmlContent += `<p class="text-red-500"><strong>Overall Error:</strong> ${operationErrorMessage}</p>`;
|
|
55
|
+
|
|
56
|
+
// Display Steps
|
|
57
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
58
|
+
const progressListId = `progress-steps-list-${contentElement.id}`; // Unique ID for the steps list
|
|
59
|
+
// Ensure the toggle icon reflects the initial state (expanded, so 'bx-chevron-up')
|
|
60
|
+
// The UL itself won't have 'hidden' class initially.
|
|
61
|
+
htmlContent += `
|
|
62
|
+
<div class="progress-section-container mt-4">
|
|
63
|
+
<h4 class="font-semibold mb-2 text-gray-700 cursor-pointer flex items-center progress-section-toggle" data-target-id="${progressListId}">
|
|
64
|
+
Progress
|
|
65
|
+
<i class='bx bx-chevron-up toggle-icon-progress ml-2 text-gray-500'></i>
|
|
66
|
+
</h4>
|
|
67
|
+
<ul id="${progressListId}" class="list-none space-y-2 border-l-2 border-blue-500 pl-4 py-2">`; // Added py-2 for padding
|
|
68
|
+
steps.forEach((step, index) => {
|
|
69
|
+
const stepTimestamp = new Date(step.timestamp).toLocaleString();
|
|
70
|
+
let stepStatusIcon = '';
|
|
71
|
+
let stepTextColor = 'text-gray-700'; // Default text color
|
|
72
|
+
|
|
73
|
+
const isLastStep = index === steps.length - 1;
|
|
74
|
+
|
|
75
|
+
if (step.errorMessage || step.status === 'failed') {
|
|
76
|
+
stepStatusIcon = "<i class='bx bx-x-circle text-red-500 mr-2'></i>";
|
|
77
|
+
stepTextColor = 'text-red-600';
|
|
78
|
+
} else if (isLastStep && isInProgressOverall) {
|
|
79
|
+
// Current active step if overall process is still running
|
|
80
|
+
stepStatusIcon = "<i class='bx bx-loader-alt bx-spin text-blue-500 mr-2'></i>";
|
|
81
|
+
stepTextColor = 'text-blue-700';
|
|
82
|
+
} else {
|
|
83
|
+
// Completed, non-failed step
|
|
84
|
+
stepStatusIcon = "<i class='bx bx-check-circle text-green-500 mr-2'></i>";
|
|
85
|
+
stepTextColor = 'text-gray-700'; // Keep default gray for completed steps, icon is green
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
htmlContent += `<li class="text-sm ${stepTextColor}">`;
|
|
89
|
+
htmlContent += `${stepStatusIcon}<strong>${step.stepName}</strong>`;
|
|
90
|
+
if (step.serverName) htmlContent += ` (Server: ${step.serverName})`;
|
|
91
|
+
htmlContent += `<span class="text-xs text-gray-500 ml-2">- ${stepTimestamp}</span>`;
|
|
92
|
+
if (step.errorMessage) {
|
|
93
|
+
htmlContent += `<p class="text-xs text-red-400 pl-6">Error: ${step.errorMessage}</p>`;
|
|
94
|
+
}
|
|
95
|
+
htmlContent += `</li>`;
|
|
96
|
+
});
|
|
97
|
+
htmlContent += '</ul>';
|
|
98
|
+
}
|
|
99
|
+
|
|
51
100
|
if (validationStatus) {
|
|
52
|
-
htmlContent += '<h4 class="font-semibold mt-
|
|
101
|
+
htmlContent += '<h4 class="font-semibold mt-4 mb-2 text-gray-700">Detailed Validation Results:</h4>';
|
|
53
102
|
htmlContent += '<ul class="list-disc list-inside space-y-1">';
|
|
54
103
|
let hasDetailedItems = false;
|
|
55
104
|
// Check for serverResults array first
|
|
@@ -98,8 +147,36 @@ export function updateOperationDisplay(data, contentElement) { // Renamed from u
|
|
|
98
147
|
htmlContent += `<p class="mt-3"><strong>PR Info:</strong> <a href="${prInfo.url}" target="_blank" class="text-blue-600 hover:underline">${prInfo.url}</a></p>`;
|
|
99
148
|
}
|
|
100
149
|
contentElement.innerHTML = htmlContent;
|
|
150
|
+
// After updating content, ensure the toggle listener is active for the new/updated progress section
|
|
151
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
152
|
+
ensureProgressToggleListener(contentElement);
|
|
153
|
+
}
|
|
101
154
|
}
|
|
102
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Ensures that a click listener is attached to the statusContentElement
|
|
158
|
+
* to handle toggling the visibility of the progress steps list.
|
|
159
|
+
* This listener is attached only once.
|
|
160
|
+
* @param {HTMLElement} statusContentElement - The parent element where progress is displayed.
|
|
161
|
+
*/
|
|
162
|
+
export function ensureProgressToggleListener(statusContentElement) {
|
|
163
|
+
if (statusContentElement && !statusContentElement.dataset.progressToggleListenerAttached) {
|
|
164
|
+
statusContentElement.addEventListener('click', (event) => {
|
|
165
|
+
const toggleHeader = event.target.closest('.progress-section-toggle');
|
|
166
|
+
if (toggleHeader) {
|
|
167
|
+
const targetId = toggleHeader.dataset.targetId;
|
|
168
|
+
const iconElement = toggleHeader.querySelector('.toggle-icon-progress');
|
|
169
|
+
// Assuming toggleSectionContent is imported from uiHandlers.js and is in scope
|
|
170
|
+
if (targetId && iconElement && typeof toggleSectionContent === 'function') {
|
|
171
|
+
toggleSectionContent(targetId, iconElement);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
statusContentElement.dataset.progressToggleListenerAttached = 'true';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
103
180
|
/**
|
|
104
181
|
* Polls the server for operation status.
|
|
105
182
|
* @param {string} categoryName - The name of the category.
|
|
@@ -107,71 +184,74 @@ export function updateOperationDisplay(data, contentElement) { // Renamed from u
|
|
|
107
184
|
* @param {string} validateBtnId - The ID of the validate button.
|
|
108
185
|
* @param {string} publishBtnId - The ID of the publish button.
|
|
109
186
|
* @param {string} operationInitiator - 'validate' or 'publish' to restore correct button text.
|
|
187
|
+
* @param {string} operationType - The type of operation to poll for (e.g., 'VALIDATION_ONLY', 'FULL_ONBOARDING').
|
|
188
|
+
* @returns {Promise<boolean>} - Promise resolving to true if polling should continue, false otherwise.
|
|
110
189
|
*/
|
|
111
|
-
export async function pollOperationStatus(categoryName, contentId, validateBtnId, publishBtnId, operationInitiator) {
|
|
190
|
+
export async function pollOperationStatus(categoryName, contentId, validateBtnId, publishBtnId, operationInitiator, operationType) {
|
|
112
191
|
const statusContentElement = document.getElementById(contentId);
|
|
192
|
+
ensureProgressToggleListener(statusContentElement); // Ensure listener is active during polling updates
|
|
193
|
+
|
|
113
194
|
const validateButton = document.getElementById(validateBtnId);
|
|
114
195
|
const publishButton = document.getElementById(publishBtnId);
|
|
115
196
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
197
|
+
// Helper function to update button states based on operation status
|
|
198
|
+
const updateButtonStates = (isCompleted = false) => {
|
|
199
|
+
if (validateButton && publishButton) {
|
|
200
|
+
if (isCompleted) {
|
|
201
|
+
// On completion, enable both buttons and restore their original state
|
|
202
|
+
validateButton.disabled = false;
|
|
203
|
+
validateButton.innerHTML = "<i class='bx bx-check-shield mr-2'></i>Validate";
|
|
204
|
+
validateButton.classList.remove('opacity-50');
|
|
205
|
+
publishButton.disabled = false;
|
|
206
|
+
publishButton.innerHTML = "<i class='bx bx-cloud-upload mr-2'></i>Publish";
|
|
207
|
+
publishButton.classList.remove('opacity-50');
|
|
208
|
+
} else {
|
|
209
|
+
// During operation, handle buttons based on which operation is running
|
|
210
|
+
if (operationInitiator === 'validate') {
|
|
211
|
+
validateButton.disabled = true;
|
|
212
|
+
validateButton.innerHTML = "<i class='bx bx-loader-alt bx-spin mr-2'></i>Validating...";
|
|
213
|
+
publishButton.disabled = true;
|
|
214
|
+
publishButton.innerHTML = "<i class='bx bx-cloud-upload mr-2'></i>Publish";
|
|
215
|
+
publishButton.classList.add('opacity-50');
|
|
216
|
+
} else if (operationInitiator === 'publish') {
|
|
217
|
+
publishButton.disabled = true;
|
|
218
|
+
publishButton.innerHTML = "<i class='bx bx-loader-alt bx-spin mr-2'></i>Publishing...";
|
|
219
|
+
validateButton.disabled = true;
|
|
220
|
+
validateButton.innerHTML = "<i class='bx bx-check-shield mr-2'></i>Validate";
|
|
221
|
+
validateButton.classList.add('opacity-50');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
// Add operationType as a query parameter
|
|
229
|
+
const response = await fetch(`/api/categories/${categoryName}/onboard/status?operationType=${encodeURIComponent(operationType)}`);
|
|
230
|
+
const result = await response.json();
|
|
231
|
+
|
|
232
|
+
if (result.success && result.data) {
|
|
151
233
|
updateOperationDisplay(result.data, statusContentElement);
|
|
152
234
|
|
|
153
235
|
const currentStatus = result.data.status ? String(result.data.status).toUpperCase() : ''; // Ensure uppercase for comparison
|
|
154
236
|
// Use string literals for status comparison, include 'succeeded'
|
|
155
237
|
if (currentStatus === 'COMPLETED' || currentStatus === 'FAILED' || currentStatus === 'SUCCEEDED') {
|
|
156
|
-
clearInterval(pollingIntervalId);
|
|
157
|
-
pollingIntervalId = null;
|
|
158
238
|
updateButtonStates(true);
|
|
239
|
+
return false; // Stop polling
|
|
159
240
|
} else {
|
|
160
241
|
// Operation is still in progress
|
|
161
242
|
updateButtonStates(false);
|
|
243
|
+
return true; // Continue polling
|
|
162
244
|
}
|
|
163
245
|
} else {
|
|
164
246
|
statusContentElement.innerHTML = `<p class="text-red-500">Error polling status: ${result.error || 'Unknown error'}</p>`;
|
|
165
|
-
clearInterval(pollingIntervalId);
|
|
166
|
-
pollingIntervalId = null;
|
|
167
247
|
updateButtonStates(true);
|
|
248
|
+
return false; // Stop polling
|
|
168
249
|
}
|
|
169
250
|
} catch (error) {
|
|
170
251
|
console.error('Error polling operation status:', error);
|
|
171
252
|
statusContentElement.innerHTML = `<p class="text-red-500">An error occurred while polling status. Please check the console.</p>`;
|
|
172
|
-
clearInterval(pollingIntervalId);
|
|
173
|
-
pollingIntervalId = null;
|
|
174
253
|
updateButtonStates(true);
|
|
254
|
+
return false; // Stop polling
|
|
175
255
|
}
|
|
176
256
|
}
|
|
177
257
|
|
|
@@ -186,6 +266,8 @@ export async function handleValidation(event, activeTab, currentSelectedCategory
|
|
|
186
266
|
const { panelId, contentId, formId, validateButtonId, publishButtonId } = getElementIdsByTab(activeTab);
|
|
187
267
|
|
|
188
268
|
const statusContentElement = document.getElementById(contentId);
|
|
269
|
+
ensureProgressToggleListener(statusContentElement); // Ensure listener is active for initial display
|
|
270
|
+
|
|
189
271
|
const onboardForm = document.getElementById(formId);
|
|
190
272
|
const validateButton = document.getElementById(validateButtonId);
|
|
191
273
|
const publishButton = document.getElementById(publishButtonId);
|
|
@@ -266,21 +348,11 @@ export async function handleValidation(event, activeTab, currentSelectedCategory
|
|
|
266
348
|
if (forExistingCategoryTab && currentSelectedCategoryData) {
|
|
267
349
|
finalFeedConfiguration = JSON.parse(JSON.stringify(currentSelectedCategoryData)); // Deep clone
|
|
268
350
|
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
(newServersData.requirements || []).forEach(newReq => {
|
|
275
|
-
const reqKey = `${newReq.type}|${newReq.name}|${newReq.version}`;
|
|
276
|
-
if (!existingReqKeys.has(reqKey)) {
|
|
277
|
-
if (!finalFeedConfiguration.requirements) {
|
|
278
|
-
finalFeedConfiguration.requirements = [];
|
|
279
|
-
}
|
|
280
|
-
finalFeedConfiguration.requirements.push(newReq);
|
|
281
|
-
existingReqKeys.add(reqKey);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
351
|
+
// Replace MCP Servers and Requirements with the current state from the form (newServersData).
|
|
352
|
+
// newServersData, generated by getFormData, already contains the correct, complete list
|
|
353
|
+
// of servers (including original, adhoc, and newly added ones) and their derived global requirements.
|
|
354
|
+
finalFeedConfiguration.mcpServers = newServersData.mcpServers || [];
|
|
355
|
+
finalFeedConfiguration.requirements = newServersData.requirements || [];
|
|
284
356
|
} else {
|
|
285
357
|
finalFeedConfiguration = newServersData;
|
|
286
358
|
}
|
|
@@ -305,12 +377,23 @@ export async function handleValidation(event, activeTab, currentSelectedCategory
|
|
|
305
377
|
|
|
306
378
|
if (result.success && result.data) {
|
|
307
379
|
updateOperationDisplay(result.data, statusContentElement);
|
|
308
|
-
|
|
380
|
+
// The onboardingId from the response is the combined ID (categoryName_operationType).
|
|
381
|
+
// We need the categoryName for polling, which we already have as a parameter.
|
|
382
|
+
// The operationType is also passed to pollOperationStatus.
|
|
383
|
+
const categoryNameForPolling = finalFeedConfiguration.name; // Use the original category name
|
|
384
|
+
const operationTypeForPolling = 'VALIDATION_ONLY'; // Validation always initiates 'VALIDATION_ONLY'
|
|
309
385
|
const initialStatus = result.data.status;
|
|
310
386
|
|
|
311
387
|
// Use string literals for status comparison, include 'succeeded'
|
|
312
|
-
|
|
313
|
-
|
|
388
|
+
const upperInitialStatus = typeof initialStatus === 'string' ? initialStatus.toUpperCase() : '';
|
|
389
|
+
if (categoryNameForPolling && upperInitialStatus !== 'COMPLETED' && upperInitialStatus !== 'FAILED' && upperInitialStatus !== 'SUCCEEDED') {
|
|
390
|
+
pollingIntervalId = setInterval(async () => {
|
|
391
|
+
const shouldContinue = await pollOperationStatus(categoryNameForPolling, contentId, validateButtonId, publishButtonId, 'validate', operationTypeForPolling);
|
|
392
|
+
if (!shouldContinue) {
|
|
393
|
+
clearInterval(pollingIntervalId);
|
|
394
|
+
pollingIntervalId = null;
|
|
395
|
+
}
|
|
396
|
+
}, POLLING_INTERVAL);
|
|
314
397
|
} else {
|
|
315
398
|
validateButton.disabled = false;
|
|
316
399
|
validateButton.innerHTML = "<i class='bx bx-check-shield mr-2'></i>Validate";
|
|
@@ -63,9 +63,19 @@ async function showServerDetails(serverName, retryCount = 0) {
|
|
|
63
63
|
throw new Error('Server data not found after retries');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
let pullRequestHtml = '';
|
|
67
|
+
if (server.feedConfiguration?.PullRequest) {
|
|
68
|
+
pullRequestHtml = `
|
|
69
|
+
<p class="mb-1 text-sm">
|
|
70
|
+
<span class="font-semibold">Pull Request:</span>
|
|
71
|
+
<a href="${server.feedConfiguration.PullRequest}" target="_blank" class="text-blue-600 hover:underline">${server.feedConfiguration.PullRequest}</a>
|
|
72
|
+
</p>`;
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
detailsDiv.innerHTML = `
|
|
67
76
|
<h3 class="text-xl font-semibold mb-2 text-gray-800">${server.displayName || server.name}</h3>
|
|
68
|
-
<p class="mb-
|
|
77
|
+
<p class="mb-1"><span class="font-semibold">Description:</span> ${server.description || 'N/A'}</p>
|
|
78
|
+
${pullRequestHtml}
|
|
69
79
|
<div id="toolMcpsList" class="mt-4">
|
|
70
80
|
<div class="animate-pulse flex space-x-4">
|
|
71
81
|
<div class="flex-1 space-y-4 py-1">
|
|
@@ -180,8 +190,13 @@ async function renderServersList(serverCategory) {
|
|
|
180
190
|
<div class="server-item-content" data-server-name="${mcpServer.name}">
|
|
181
191
|
<div class="server-item-info" style="width: 100%; box-sizing: border-box;">
|
|
182
192
|
<div class="server-item-header">
|
|
183
|
-
<div class="flex items-center">
|
|
184
|
-
<h5 class="font-semibold text-gray-800">${mcpServer.displayName || mcpServer.name}</h5>
|
|
193
|
+
<div class="flex items-center flex-wrap">
|
|
194
|
+
<h5 class="font-semibold text-gray-800 mr-2">${mcpServer.displayName || mcpServer.name}</h5>
|
|
195
|
+
${mcpServer.systemTags && Object.keys(mcpServer.systemTags).length > 0 ? `
|
|
196
|
+
<div class="flex flex-wrap gap-1 items-center">
|
|
197
|
+
${Object.entries(mcpServer.systemTags).map(([key, value]) => `<span class="text-xs bg-purple-100 text-purple-700 px-2 py-0.5 rounded-full">${key}: ${value}</span>`).join('')}
|
|
198
|
+
</div>
|
|
199
|
+
` : ''}
|
|
185
200
|
${mcpServer.repository || serverCategory.feedConfiguration?.repository ? (() => {
|
|
186
201
|
const repoUrl = mcpServer.repository || serverCategory.feedConfiguration?.repository;
|
|
187
202
|
const isGithub = repoUrl.toLowerCase().includes('github.com');
|
|
@@ -201,7 +216,7 @@ async function renderServersList(serverCategory) {
|
|
|
201
216
|
</a>`
|
|
202
217
|
})() : ''}
|
|
203
218
|
</div>
|
|
204
|
-
<p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
|
|
219
|
+
<p class="text-sm text-gray-600 mb-1 mt-1">${mcpServer.description || 'No description'}</p>
|
|
205
220
|
</div>
|
|
206
221
|
<div class="flex flex-col mt-3">
|
|
207
222
|
<span class="text-xs font-semibold mb-2">Client Status:</span>
|
|
@@ -72,12 +72,24 @@ function renderServerCategoryList(servers) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
let systemTagsHtml = '';
|
|
76
|
+
if (server.feedConfiguration?.systemTags && Object.keys(server.feedConfiguration.systemTags).length > 0) {
|
|
77
|
+
systemTagsHtml += '<div class="flex flex-wrap gap-1 ml-2">'; // Added ml-2 for spacing
|
|
78
|
+
for (const [key, value] of Object.entries(server.feedConfiguration.systemTags)) {
|
|
79
|
+
systemTagsHtml += `<span class="text-xs bg-blue-100 text-blue-700 px-2 py-0.5 rounded-full">${key}: ${value}</span>`;
|
|
80
|
+
}
|
|
81
|
+
systemTagsHtml += '</div>';
|
|
82
|
+
}
|
|
83
|
+
|
|
75
84
|
return `
|
|
76
85
|
<div class="server-item border border-gray-200 p-3 rounded hover:bg-gray-50 cursor-pointer transition duration-150 ease-in-out"
|
|
77
86
|
onclick="navigateToCategory('${server.name}')"
|
|
78
87
|
data-server-name="${server.name}">
|
|
79
88
|
<h3 class="font-semibold text-gray-800">${server.displayName || server.name}</h3>
|
|
80
|
-
<
|
|
89
|
+
<div class="text-sm text-gray-500 flex items-center mt-1">
|
|
90
|
+
${statusHtml}
|
|
91
|
+
${systemTagsHtml}
|
|
92
|
+
</div>
|
|
81
93
|
</div>
|
|
82
94
|
`;
|
|
83
95
|
}).join('');
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
<i class='bx bx-server mr-2 text-blue-600'></i>
|
|
127
127
|
MCP Servers
|
|
128
128
|
</h2>
|
|
129
|
-
<button type="button"
|
|
129
|
+
<button type="button" id="addServerBtnNewCategory"
|
|
130
130
|
class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 flex items-center text-sm">
|
|
131
131
|
<i class='bx bx-plus mr-2'></i>
|
|
132
132
|
Add MCP Server
|
package/dist/web/server.js
CHANGED
|
@@ -205,25 +205,38 @@ app.post('/api/categories/onboard/validate', async (req, res) => {
|
|
|
205
205
|
app.get('/api/categories/:categoryName/onboard/status', async (req, res) => {
|
|
206
206
|
try {
|
|
207
207
|
const { categoryName } = req.params;
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
const { operationType } = req.query;
|
|
209
|
+
if (!operationType) {
|
|
210
|
+
return res.status(400).json({
|
|
211
|
+
success: false,
|
|
212
|
+
error: 'operationType query parameter is required.'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Validate operationType if necessary (e.g., check against known OperationType values)
|
|
216
|
+
// For now, we'll assume it's a valid OperationType string.
|
|
217
|
+
const validOperationType = operationType;
|
|
218
|
+
const status = await onboardStatusManager.getStatus(categoryName, validOperationType);
|
|
210
219
|
if (!status) {
|
|
211
220
|
return res.status(404).json({
|
|
212
221
|
success: false,
|
|
213
|
-
error: `No active operation found for category ${categoryName}`
|
|
222
|
+
error: `No active operation found for category ${categoryName} with operation type ${validOperationType}`
|
|
214
223
|
});
|
|
215
224
|
}
|
|
216
225
|
// Construct the response data based on the retrieved OnboardStatus
|
|
226
|
+
const lastStepName = status.steps && status.steps.length > 0 ? status.steps[status.steps.length - 1].stepName : undefined;
|
|
217
227
|
const responseData = {
|
|
218
|
-
onboardingId: status.onboardingId, // This
|
|
228
|
+
onboardingId: status.onboardingId, // This is categoryName_operationType
|
|
219
229
|
status: status.status,
|
|
220
|
-
message:
|
|
230
|
+
message: lastStepName || status.errorMessage || 'Processing...',
|
|
221
231
|
lastQueried: new Date().toISOString(),
|
|
232
|
+
steps: status.steps, // Include the steps array in the response
|
|
222
233
|
...(status.validationStatus && { validationStatus: status.validationStatus }),
|
|
223
234
|
...(status.prInfo && { prInfo: status.prInfo }),
|
|
224
235
|
...(status.result && { result: status.result }),
|
|
225
236
|
...(status.errorMessage && { errorMessage: status.errorMessage }),
|
|
226
|
-
|
|
237
|
+
operationType: status.operationType, // Always include operationType from the status object
|
|
238
|
+
// Attempt to include feedConfiguration if available, especially for SUCCEEDED VALIDATION_ONLY
|
|
239
|
+
...(status.operationType === 'VALIDATION_ONLY' && status.status === OnboardingProcessStatus.SUCCEEDED && status.result?.feedConfiguration && { feedConfiguration: status.result.feedConfiguration }),
|
|
227
240
|
};
|
|
228
241
|
const response = {
|
|
229
242
|
success: true,
|