imcp 0.1.1 → 0.1.2
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/index.js +1 -45
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -5
- package/dist/core/installers/clients/BaseClientInstaller.js +40 -38
- package/dist/core/installers/clients/ClientInstaller.d.ts +9 -9
- package/dist/core/installers/clients/ClientInstaller.js +105 -99
- package/dist/core/installers/requirements/BaseInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.js +46 -12
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +11 -1
- package/dist/core/installers/requirements/GeneralInstaller.js +46 -10
- package/dist/core/installers/requirements/InstallerFactory.d.ts +3 -1
- package/dist/core/installers/requirements/InstallerFactory.js +3 -2
- package/dist/core/installers/requirements/NpmInstaller.d.ts +4 -2
- package/dist/core/installers/requirements/NpmInstaller.js +38 -22
- package/dist/core/installers/requirements/PipInstaller.d.ts +3 -1
- package/dist/core/installers/requirements/PipInstaller.js +58 -36
- package/dist/core/installers/requirements/RequirementInstaller.d.ts +4 -1
- package/dist/core/loaders/InstallOperationManager.d.ts +115 -0
- package/dist/core/loaders/InstallOperationManager.js +311 -0
- package/dist/core/loaders/SystemSettingsManager.d.ts +54 -0
- package/dist/core/loaders/SystemSettingsManager.js +257 -0
- package/dist/core/metadatas/recordingConstants.d.ts +44 -0
- package/dist/core/metadatas/recordingConstants.js +45 -0
- package/dist/core/metadatas/types.d.ts +21 -0
- package/dist/core/onboard/InstallOperationManager.d.ts +23 -0
- package/dist/core/onboard/InstallOperationManager.js +144 -0
- package/dist/core/onboard/OnboardStatusManager.js +2 -1
- package/dist/core/validators/StdioServerValidator.js +4 -3
- package/dist/services/InstallationService.d.ts +2 -37
- package/dist/services/InstallationService.js +45 -313
- package/dist/services/MCPManager.d.ts +1 -1
- package/dist/services/MCPManager.js +4 -58
- package/dist/services/RequirementService.d.ts +85 -12
- package/dist/services/RequirementService.js +488 -49
- package/dist/services/ServerService.d.ts +0 -6
- package/dist/services/ServerService.js +0 -74
- package/dist/utils/adoUtils.js +6 -3
- package/dist/utils/logger.js +1 -1
- package/dist/utils/macroExpressionUtils.js +3 -25
- package/dist/utils/osUtils.d.ts +22 -1
- package/dist/utils/osUtils.js +92 -1
- package/dist/utils/versionUtils.d.ts +20 -1
- package/dist/utils/versionUtils.js +51 -4
- package/dist/web/public/css/modal.css +292 -1
- package/dist/web/public/css/serverDetails.css +14 -1
- package/dist/web/public/index.html +122 -20
- package/dist/web/public/js/flights/flights.js +1 -0
- package/dist/web/public/js/modal/index.js +8 -14
- package/dist/web/public/js/modal/installModal.js +3 -4
- package/dist/web/public/js/modal/installation.js +122 -137
- package/dist/web/public/js/modal/loadingModal.js +155 -25
- package/dist/web/public/js/modal/messageQueue.js +45 -101
- package/dist/web/public/js/modal/modalSetup.js +125 -43
- package/dist/web/public/js/modal/modalUtils.js +0 -12
- package/dist/web/public/js/modal.js +23 -10
- package/dist/web/public/js/onboard/publishHandler.js +22 -20
- package/dist/web/public/js/serverCategoryDetails.js +60 -11
- package/dist/web/public/js/serverCategoryList.js +2 -2
- package/dist/web/public/js/settings.js +314 -0
- package/dist/web/public/settings.html +135 -0
- package/dist/web/public/styles.css +32 -0
- package/dist/web/server.js +82 -0
- package/memory-bank/activeContext.md +13 -1
- package/memory-bank/decisionLog.md +63 -0
- package/memory-bank/progress.md +30 -0
- package/memory-bank/systemPatterns.md +7 -0
- package/package.json +1 -1
- package/src/cli/index.ts +1 -48
- package/src/core/installers/clients/BaseClientInstaller.ts +64 -50
- package/src/core/installers/clients/ClientInstaller.ts +130 -130
- package/src/core/installers/requirements/BaseInstaller.ts +9 -1
- package/src/core/installers/requirements/CommandInstaller.ts +47 -13
- package/src/core/installers/requirements/GeneralInstaller.ts +48 -10
- package/src/core/installers/requirements/InstallerFactory.ts +4 -3
- package/src/core/installers/requirements/NpmInstaller.ts +90 -68
- package/src/core/installers/requirements/PipInstaller.ts +81 -55
- package/src/core/installers/requirements/RequirementInstaller.ts +4 -3
- package/src/core/loaders/InstallOperationManager.ts +367 -0
- package/src/core/loaders/SystemSettingsManager.ts +278 -0
- package/src/core/metadatas/recordingConstants.ts +62 -0
- package/src/core/metadatas/types.ts +23 -0
- package/src/core/onboard/OnboardStatusManager.ts +2 -1
- package/src/core/validators/StdioServerValidator.ts +4 -3
- package/src/services/InstallationService.ts +54 -399
- package/src/services/MCPManager.ts +4 -77
- package/src/services/RequirementService.ts +564 -67
- package/src/services/ServerService.ts +0 -90
- package/src/utils/adoUtils.ts +6 -4
- package/src/utils/logger.ts +1 -1
- package/src/utils/macroExpressionUtils.ts +4 -21
- package/src/utils/osUtils.ts +92 -1
- package/src/utils/versionUtils.ts +71 -19
- package/src/web/public/css/modal.css +292 -1
- package/src/web/public/css/serverDetails.css +14 -1
- package/src/web/public/index.html +122 -20
- package/src/web/public/js/flights/flights.js +1 -1
- package/src/web/public/js/modal/index.js +8 -14
- package/src/web/public/js/modal/installModal.js +3 -4
- package/src/web/public/js/modal/installation.js +122 -137
- package/src/web/public/js/modal/loadingModal.js +155 -25
- package/src/web/public/js/modal/modalSetup.js +125 -43
- package/src/web/public/js/modal/modalUtils.js +0 -12
- package/src/web/public/js/modal.js +23 -10
- package/src/web/public/js/onboard/publishHandler.js +22 -20
- package/src/web/public/js/serverCategoryDetails.js +60 -11
- package/src/web/public/js/serverCategoryList.js +2 -2
- package/src/web/public/js/settings.js +314 -0
- package/src/web/public/settings.html +135 -0
- package/src/web/public/styles.css +32 -0
- package/src/web/server.ts +85 -0
- package/src/web/public/js/modal/messageQueue.js +0 -112
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { showToast, showConfirm } from '../notifications.js';
|
|
2
|
-
import { showInstallLoadingModal } from './loadingModal.js';
|
|
3
|
-
import { delayedAppendInstallLoadingMessage } from './messageQueue.js';
|
|
2
|
+
import { showInstallLoadingModal, updateOverallInstallStatus } from './loadingModal.js';
|
|
3
|
+
// import { delayedAppendInstallLoadingMessage } from './messageQueue.js'; // No longer used
|
|
4
4
|
import { uninstallTools } from './installation.js';
|
|
5
5
|
import { handleBulkClientInstall } from './installation.js';
|
|
6
6
|
import { compareVersions } from './versionUtils.js';
|
|
@@ -56,17 +56,31 @@ export function setupEnvironmentVariables(mcpServer, envInputsDiv, targetData) {
|
|
|
56
56
|
const envRequirements = mcpServer.installation?.['env'] || mcpServer.installation?.env || {};
|
|
57
57
|
addEnvironmentTitle(envInputsDiv);
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
// Fetch system settings to get userConfigurations for env defaults
|
|
60
|
+
fetch('/api/settings')
|
|
61
|
+
.then(response => response.json())
|
|
62
|
+
.then(data => {
|
|
63
|
+
const userConfigurations = (data && data.data && data.data.userConfigurations) ? data.data.userConfigurations : {};
|
|
64
|
+
if (Object.keys(envRequirements).length === 0) {
|
|
65
|
+
addNoEnvMessage(envInputsDiv);
|
|
66
|
+
} else {
|
|
67
|
+
createEnvironmentInputs(envRequirements, envInputsDiv, targetData.clientMcpSettings, mcpServer.name, userConfigurations);
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
.catch(() => {
|
|
71
|
+
// fallback to old logic if fetch fails
|
|
72
|
+
if (Object.keys(envRequirements).length === 0) {
|
|
73
|
+
addNoEnvMessage(envInputsDiv);
|
|
74
|
+
} else {
|
|
75
|
+
createEnvironmentInputs(envRequirements, envInputsDiv, targetData.clientMcpSettings, mcpServer.name, {});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
/**
|
|
67
81
|
* Set up installation arguments section in the modal
|
|
68
82
|
*/
|
|
69
|
-
export function setupInstallationArguments(installation, modalArguments, mcpServer) {
|
|
83
|
+
export function setupInstallationArguments(installation, modalArguments, categoryName, mcpServer) {
|
|
70
84
|
// For SSE mode, don't show arguments section at all
|
|
71
85
|
if (mcpServer?.mode === 'sse') {
|
|
72
86
|
modalArguments.style.display = 'none';
|
|
@@ -88,7 +102,7 @@ export function setupInstallationArguments(installation, modalArguments, mcpServ
|
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
if (installation.command === 'python' || installation.command.includes('python')) {
|
|
91
|
-
addPythonEnvironmentInput(modalArguments);
|
|
105
|
+
addPythonEnvironmentInput(categoryName, mcpServer.name, modalArguments);
|
|
92
106
|
}
|
|
93
107
|
}
|
|
94
108
|
|
|
@@ -157,36 +171,90 @@ export function setupFormSubmitHandler(form, envInputsDiv, modalArguments, modal
|
|
|
157
171
|
});
|
|
158
172
|
}
|
|
159
173
|
|
|
160
|
-
|
|
174
|
+
// Only POST userConfigurations and/or pythonEnvs if there is a difference, then proceed with install
|
|
175
|
+
fetch('/api/settings')
|
|
176
|
+
.then(response => response.json())
|
|
177
|
+
.then(data => {
|
|
178
|
+
const userConfigurations = (data && data.data && data.data.userConfigurations) ? data.data.userConfigurations : {};
|
|
179
|
+
const pythonEnvs = (data && data.data && data.data.pythonEnvs) ? data.data.pythonEnvs : {};
|
|
180
|
+
const updatedUserConfigurations = { ...userConfigurations };
|
|
181
|
+
const updatedPythonEnvs = { ...pythonEnvs };
|
|
182
|
+
|
|
183
|
+
Object.keys(envVars).forEach(key => {
|
|
184
|
+
updatedUserConfigurations[key] = envVars[key];
|
|
185
|
+
});
|
|
161
186
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
187
|
+
// Check for userConfigurations difference
|
|
188
|
+
let needsUserConfigUpdate = false;
|
|
189
|
+
const allUserConfigKeys = new Set([...Object.keys(userConfigurations), ...Object.keys(envVars)]);
|
|
190
|
+
for (const key of allUserConfigKeys) {
|
|
191
|
+
if (userConfigurations[key] !== updatedUserConfigurations[key]) {
|
|
192
|
+
needsUserConfigUpdate = true;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
169
196
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
197
|
+
// Check for pythonEnvs difference
|
|
198
|
+
let needsPythonEnvUpdate = false;
|
|
199
|
+
if (pythonEnv !== undefined && pythonEnv !== pythonEnvs[`${categoryName}:${serverName}`]) {
|
|
200
|
+
updatedPythonEnvs[`${categoryName}:${serverName}`] = pythonEnv;
|
|
201
|
+
needsPythonEnvUpdate = true;
|
|
202
|
+
}
|
|
177
203
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
204
|
+
// If either needs update, POST the merged object
|
|
205
|
+
if (needsUserConfigUpdate || needsPythonEnvUpdate) {
|
|
206
|
+
const postBody = {};
|
|
207
|
+
if (needsUserConfigUpdate) postBody.userConfigurations = updatedUserConfigurations;
|
|
208
|
+
if (needsPythonEnvUpdate) postBody.pythonEnvs = updatedPythonEnvs;
|
|
209
|
+
fetch('/api/settings', {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
headers: { 'Content-Type': 'application/json' },
|
|
212
|
+
body: JSON.stringify(postBody)
|
|
213
|
+
}).then(() => {
|
|
214
|
+
proceedInstall();
|
|
215
|
+
}).catch(() => {
|
|
216
|
+
proceedInstall();
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
proceedInstall();
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
.catch(() => {
|
|
223
|
+
proceedInstall();
|
|
224
|
+
});
|
|
184
225
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
226
|
+
function proceedInstall() {
|
|
227
|
+
const hasRequirementsToUpdate = requirementsToUpdate.length > 0;
|
|
228
|
+
|
|
229
|
+
const uninstallBtn = document.querySelector('.uninstall-btn');
|
|
230
|
+
if (!uninstallBtn || !uninstallBtn.matches(':active')) {
|
|
231
|
+
const selectedTargets = window.selectedClients;
|
|
232
|
+
if (selectedTargets.length === 0 && !hasRequirementsToUpdate) {
|
|
233
|
+
showToast('Please select at least one client to configure.', 'error');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
let installingMessage = "Starting installation...";
|
|
238
|
+
const serverStatus = serverStatuses[serverName] || { installedStatus: {} };
|
|
239
|
+
if (selectedTargets.length > 0) {
|
|
240
|
+
const target = selectedTargets[0];
|
|
241
|
+
const msg = serverStatus.installedStatus?.[target]?.message;
|
|
242
|
+
if (msg) installingMessage = msg;
|
|
243
|
+
}
|
|
188
244
|
|
|
189
|
-
|
|
245
|
+
const serverInstallOptions = {
|
|
246
|
+
targetClients: selectedTargets,
|
|
247
|
+
env: envVars,
|
|
248
|
+
args: args,
|
|
249
|
+
settings: pythonEnv ? { pythonEnv: pythonEnv } : {}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (requirementsToUpdate.length > 0) {
|
|
253
|
+
serverInstallOptions.requirements = requirementsToUpdate;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
handleBulkClientInstall(categoryName, serverName, selectedTargets, envVars, installingMessage, serverData, serverInstallOptions);
|
|
257
|
+
}
|
|
190
258
|
}
|
|
191
259
|
};
|
|
192
260
|
}
|
|
@@ -288,11 +356,12 @@ function createUninstallButton(target, categoryName, serverName) {
|
|
|
288
356
|
};
|
|
289
357
|
|
|
290
358
|
try {
|
|
291
|
-
|
|
359
|
+
updateOverallInstallStatus('in-progress', `Uninstalling ${serverName} from ${target}...`);
|
|
292
360
|
await uninstallTools(categoryName, serverList, [target]);
|
|
361
|
+
// uninstallTools will now handle its own final status update via updateOverallInstallStatus
|
|
293
362
|
} catch (error) {
|
|
294
|
-
|
|
295
|
-
throw
|
|
363
|
+
updateOverallInstallStatus('failed', `Error during uninstall: ${error.message}`);
|
|
364
|
+
// No need to throw here if uninstallTools handles its errors by updating status
|
|
296
365
|
}
|
|
297
366
|
}
|
|
298
367
|
return false;
|
|
@@ -326,7 +395,7 @@ function addNoEnvMessage(envInputsDiv) {
|
|
|
326
395
|
envInputsDiv.appendChild(noEnvMessage);
|
|
327
396
|
}
|
|
328
397
|
|
|
329
|
-
function createEnvironmentInputs(envRequirements, envInputsDiv, clientSettings, serverName) {
|
|
398
|
+
function createEnvironmentInputs(envRequirements, envInputsDiv, clientSettings, serverName, userConfigurations = {}) {
|
|
330
399
|
Object.keys(envRequirements).forEach(key => {
|
|
331
400
|
const req = envRequirements[key];
|
|
332
401
|
const inputId = `env_${key}`;
|
|
@@ -346,11 +415,13 @@ function createEnvironmentInputs(envRequirements, envInputsDiv, clientSettings,
|
|
|
346
415
|
input.required = req.Required;
|
|
347
416
|
input.className = 'input-field';
|
|
348
417
|
|
|
349
|
-
// For default value, first check
|
|
418
|
+
// For default value, first check userConfigurations, then client settings, then provided default
|
|
350
419
|
let defaultValue = req.Default || '';
|
|
351
420
|
|
|
352
|
-
//
|
|
353
|
-
if (
|
|
421
|
+
// Use userConfigurations if present
|
|
422
|
+
if (userConfigurations && userConfigurations[key]) {
|
|
423
|
+
defaultValue = userConfigurations[key];
|
|
424
|
+
} else if (clientSettings && clientSettings.MSRooCode &&
|
|
354
425
|
clientSettings.MSRooCode.mcpServers &&
|
|
355
426
|
clientSettings.MSRooCode.mcpServers[serverName] &&
|
|
356
427
|
clientSettings.MSRooCode.mcpServers[serverName].env &&
|
|
@@ -416,7 +487,7 @@ function createArgumentInput(value = '') {
|
|
|
416
487
|
return argWrapper;
|
|
417
488
|
}
|
|
418
489
|
|
|
419
|
-
function addPythonEnvironmentInput(modalArguments) {
|
|
490
|
+
function addPythonEnvironmentInput(categoryName, serverName, modalArguments) {
|
|
420
491
|
const pythonEnvWrapper = document.createElement('div');
|
|
421
492
|
pythonEnvWrapper.className = 'mt-4';
|
|
422
493
|
|
|
@@ -433,12 +504,23 @@ function addPythonEnvironmentInput(modalArguments) {
|
|
|
433
504
|
|
|
434
505
|
const envDescription = document.createElement('p');
|
|
435
506
|
envDescription.className = 'text-xs text-gray-500 mt-1';
|
|
436
|
-
envDescription.textContent = 'Specify the Python
|
|
507
|
+
envDescription.textContent = 'Specify the Python exectable file(e.g. C:/python312/python) to use for installation. Leave empty to use system default. You can specify value in Settings page';
|
|
437
508
|
|
|
438
509
|
pythonEnvWrapper.appendChild(pythonEnvLabel);
|
|
439
510
|
pythonEnvWrapper.appendChild(pythonEnvInput);
|
|
440
511
|
pythonEnvWrapper.appendChild(envDescription);
|
|
441
512
|
modalArguments.appendChild(pythonEnvWrapper);
|
|
513
|
+
// Fetch system settings and set default value for python_env
|
|
514
|
+
fetch('/api/settings')
|
|
515
|
+
.then(response => response.json())
|
|
516
|
+
.then(data => {
|
|
517
|
+
if (data && data.data && data.data.pythonEnvs) {
|
|
518
|
+
pythonEnvInput.value = data.data.pythonEnvs[`${categoryName}:${serverName}`] || data.data.pythonEnvs['system'] || '';
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
.catch(() => {
|
|
522
|
+
// Ignore errors, leave input empty
|
|
523
|
+
});
|
|
442
524
|
}
|
|
443
525
|
|
|
444
526
|
function renderRequirements(serverRequirements, requirements, categoryName, serverName) {
|
|
@@ -17,18 +17,6 @@ export function closeModal() {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Close modal if clicked outside content
|
|
22
|
-
*/
|
|
23
|
-
export function setupModalOutsideClick() {
|
|
24
|
-
window.onclick = function (event) {
|
|
25
|
-
const installModal = document.getElementById('installModal');
|
|
26
|
-
if (event.target == installModal) {
|
|
27
|
-
closeModal();
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
20
|
/**
|
|
33
21
|
* Setup toggle switch styles
|
|
34
22
|
*/
|
|
@@ -2,28 +2,41 @@
|
|
|
2
2
|
import {
|
|
3
3
|
showInstallModal,
|
|
4
4
|
closeModal,
|
|
5
|
-
setupModalOutsideClick,
|
|
6
5
|
uninstallTools,
|
|
7
6
|
showInstallLoadingModal,
|
|
8
|
-
appendInstallLoadingMessage,
|
|
9
|
-
hideInstallLoadingModal
|
|
7
|
+
// appendInstallLoadingMessage, // Removed
|
|
8
|
+
hideInstallLoadingModal,
|
|
9
|
+
// Potentially add updateOverallInstallStatus, addInstallationStep if needed from ./modal/index.js
|
|
10
10
|
} from './modal/index.js';
|
|
11
11
|
|
|
12
12
|
// Re-export all modal functionality
|
|
13
13
|
export {
|
|
14
14
|
showInstallModal,
|
|
15
15
|
closeModal,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
uninstallTools,
|
|
17
|
+
showInstallLoadingModal, // Added to exports
|
|
18
|
+
hideInstallLoadingModal // Added to exports
|
|
19
|
+
// Potentially add updateOverallInstallStatus, addInstallationStep to exports
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
// Make certain functions available globally
|
|
21
23
|
window.showInstallModal = showInstallModal;
|
|
22
24
|
window.showInstallLoadingModal = showInstallLoadingModal;
|
|
23
|
-
window.appendInstallLoadingMessage = appendInstallLoadingMessage;
|
|
25
|
+
// window.appendInstallLoadingMessage = appendInstallLoadingMessage; // Removed
|
|
24
26
|
window.hideInstallLoadingModal = hideInstallLoadingModal;
|
|
25
27
|
|
|
26
|
-
//
|
|
27
|
-
document.addEventListener('
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// Listen for the custom event to refresh the main modal content
|
|
29
|
+
document.addEventListener('refreshMainModalContent', () => {
|
|
30
|
+
console.log('[ModalJS] Received refreshMainModalContent event. Refreshing main modal.');
|
|
31
|
+
const lastSelectedCategory = localStorage.getItem('lastSelectedCategory');
|
|
32
|
+
const lastSelectedServerName = localStorage.getItem('lastSelectedServerName');
|
|
33
|
+
|
|
34
|
+
const isCategoryValid = lastSelectedCategory && lastSelectedCategory.trim() !== '' && lastSelectedCategory !== 'undefined' && lastSelectedCategory !== 'null';
|
|
35
|
+
const isServerNameValid = lastSelectedServerName && lastSelectedServerName.trim() !== '' && lastSelectedServerName !== 'undefined' && lastSelectedServerName !== 'null';
|
|
36
|
+
|
|
37
|
+
if (isCategoryValid && isServerNameValid) {
|
|
38
|
+
window.showInstallModal(lastSelectedCategory, lastSelectedServerName);
|
|
39
|
+
} else {
|
|
40
|
+
console.warn(`[ModalJS] Not refreshing modal. Category valid: ${isCategoryValid} (value: "${lastSelectedCategory}"), ServerName valid: ${isServerNameValid} (value: "${lastSelectedServerName}")`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
@@ -25,9 +25,9 @@ export async function handlePublish(event, activeTab, currentSelectedCategoryDat
|
|
|
25
25
|
const statusContentElement = document.getElementById(contentId);
|
|
26
26
|
// Ensure the progress toggle listener is attached when handlePublish is called
|
|
27
27
|
if (typeof ensureProgressToggleListener === 'function') { // Check if imported correctly
|
|
28
|
-
|
|
28
|
+
ensureProgressToggleListener(statusContentElement);
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
const onboardForm = document.getElementById(formId);
|
|
32
32
|
const validateButton = document.getElementById(validateButtonId);
|
|
33
33
|
const publishButton = document.getElementById(publishButtonId);
|
|
@@ -41,30 +41,32 @@ export async function handlePublish(event, activeTab, currentSelectedCategoryDat
|
|
|
41
41
|
// Validate form fields
|
|
42
42
|
const validationResult = validateFormFields(onboardForm, activeTab);
|
|
43
43
|
if (!validationResult.isValid) {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
showToast('Please fix all validation errors before proceeding.', 'error');
|
|
45
|
+
return;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
let hasErrors = false;
|
|
49
|
+
|
|
48
50
|
if (activeTab === 'create-category') {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
const formData = getFormData(onboardForm, false);
|
|
52
|
+
if (!formData.mcpServers || formData.mcpServers.length === 0) {
|
|
53
|
+
showToast('At least one MCP server must be configured for a new category.', 'error');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check category name format
|
|
58
|
+
const nameInput = onboardForm.querySelector('input[name="name"]');
|
|
59
|
+
if (nameInput && nameInput.value.trim()) {
|
|
60
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(nameInput.value.trim())) {
|
|
61
|
+
showValidationMessage(nameInput, 'Only alphanumeric characters, hyphens, and underscores allowed', true);
|
|
62
|
+
hasErrors = true;
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
|
-
}
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
if (hasErrors) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
showToast('Please fix all validation errors before proceeding.', 'error');
|
|
69
|
+
return;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
publishButton.disabled = true;
|
|
@@ -146,7 +148,7 @@ export async function handlePublish(event, activeTab, currentSelectedCategoryDat
|
|
|
146
148
|
statusContentElement.innerHTML = `<p class="text-red-500">${errorMessage}</p>`;
|
|
147
149
|
}
|
|
148
150
|
showToast(errorMessage, 'error');
|
|
149
|
-
|
|
151
|
+
|
|
150
152
|
// Restore buttons to their original state fully
|
|
151
153
|
publishButton.disabled = false;
|
|
152
154
|
publishButton.innerHTML = "<i class='bx bx-cloud-upload mr-2'></i>Publish";
|
|
@@ -161,6 +161,38 @@ async function showServerDetails(serverName, retryCount = 0) {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Checks if any defined requirement for an MCP server has a pending update.
|
|
166
|
+
* An update is pending if a requirement has an `availableUpdate` or if its installed version
|
|
167
|
+
* differs from the version defined in the feed.
|
|
168
|
+
* @param {object} mcpServer - The MCP server configuration object from the feed.
|
|
169
|
+
* @param {object} requirementsStatus - The status of requirements for this server, typically from `installationStatus.requirementsStatus`.
|
|
170
|
+
* @returns {{ needsUpdate: boolean, updateMessage: string|null }} - True and message if update is available, else false/null.
|
|
171
|
+
*/
|
|
172
|
+
function checkNeedsRequirementUpdate(mcpServer, requirementsStatus) {
|
|
173
|
+
const definedReqs = mcpServer?.dependencies?.requirements || [];
|
|
174
|
+
if (definedReqs.length === 0) {
|
|
175
|
+
return false; // No requirements defined in the feed for this server.
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const currentReqsStatus = requirementsStatus || {};
|
|
179
|
+
|
|
180
|
+
for (const defReq of definedReqs) {
|
|
181
|
+
const alias = defReq.alias || defReq.name;
|
|
182
|
+
if (!alias) continue;
|
|
183
|
+
|
|
184
|
+
const statusEntry = currentReqsStatus[alias];
|
|
185
|
+
|
|
186
|
+
if (statusEntry) {
|
|
187
|
+
// Check 1: Explicit 'availableUpdate' information
|
|
188
|
+
if (statusEntry.availableUpdate && statusEntry.availableUpdate.version) {
|
|
189
|
+
return {needsUpdate: true, updateMessage: `${statusEntry.name}: ${statusEntry.availableUpdate.message}` || null};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return { needsUpdate: false, updateMessage: null };
|
|
194
|
+
}
|
|
195
|
+
|
|
164
196
|
async function renderServersList(serverCategory) {
|
|
165
197
|
try {
|
|
166
198
|
const targetResponse = await fetch('/api/targets');
|
|
@@ -239,17 +271,34 @@ async function renderServersList(serverCategory) {
|
|
|
239
271
|
</div>
|
|
240
272
|
</div>
|
|
241
273
|
<div class="action-buttons">
|
|
242
|
-
${
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
274
|
+
${(() => {
|
|
275
|
+
const serverInstallationStatus = serverCategory.installationStatus;
|
|
276
|
+
const requirementsStatus = serverInstallationStatus?.requirementsStatus;
|
|
277
|
+
// dependencies is a simple array of names
|
|
278
|
+
const { needsUpdate, updateMessage } = checkNeedsRequirementUpdate(mcpServer, requirementsStatus);
|
|
279
|
+
|
|
280
|
+
if (isInstalled) {
|
|
281
|
+
return `
|
|
282
|
+
<button onclick="event.stopPropagation(); window.uninstallTools('${serverCategory.name}', ['${mcpServer.name}'])"
|
|
283
|
+
class="bg-red-500 hover:bg-red-700 text-white text-sm font-bold py-2 px-4 rounded-full shadow-sm ease-in-out">
|
|
284
|
+
Uninstall
|
|
285
|
+
</button>`;
|
|
286
|
+
} else {
|
|
287
|
+
let buttonText = 'Setup';
|
|
288
|
+
let titleAttr = '';
|
|
289
|
+
if (needsUpdate) {
|
|
290
|
+
buttonText = 'Update';
|
|
291
|
+
if (updateMessage) {
|
|
292
|
+
titleAttr = ` title="${updateMessage.replace(/"/g, '"')}"`;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return `
|
|
296
|
+
<button onclick="event.stopPropagation(); window.showInstallModal('${serverCategory.name}', '${mcpServer.name}')"
|
|
297
|
+
class="${needsUpdate ? 'btn-update' : 'bg-blue-500 hover:bg-blue-700'} text-white text-xs font-bold py-2 px-4 rounded-full shadow-sm ease-in-out"${titleAttr}>
|
|
298
|
+
${buttonText}
|
|
299
|
+
</button>`;
|
|
300
|
+
}
|
|
301
|
+
})()}
|
|
253
302
|
</div>
|
|
254
303
|
${hasEnvRequirements ? `<div class="mt-3 text-xs text-blue-600">
|
|
255
304
|
<svg class="w-3 h-3 inline mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -128,8 +128,8 @@ function renderServerCategoryList(servers) {
|
|
|
128
128
|
statusText = "Partial Configured";
|
|
129
129
|
} else {
|
|
130
130
|
// No tools installed
|
|
131
|
-
colorClass = "text-
|
|
132
|
-
icon = '<svg class="w-5 h-5 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="
|
|
131
|
+
colorClass = "text-yellow-600 bg-orange-50";
|
|
132
|
+
icon = '<svg class="w-5 h-5 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM10 13a1 1 0 110-2 1 1 0 010 2zm-1.75-5.75a.75.75 0 00-1.5 0v3a.75.75 0 001.5 0v-3z" clip-rule="evenodd" /></svg>';
|
|
133
133
|
statusText = "Not Configured";
|
|
134
134
|
}
|
|
135
135
|
|