imcp 0.0.1
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/.github/ISSUE_TEMPLATE/JitAccess.yml +28 -0
- package/.github/acl/access.yml +20 -0
- package/.github/compliance/inventory.yml +5 -0
- package/.github/policies/jit.yml +19 -0
- package/README.md +137 -0
- package/dist/cli/commands/install.d.ts +2 -0
- package/dist/cli/commands/install.js +105 -0
- package/dist/cli/commands/list.d.ts +2 -0
- package/dist/cli/commands/list.js +90 -0
- package/dist/cli/commands/pull.d.ts +2 -0
- package/dist/cli/commands/pull.js +17 -0
- package/dist/cli/commands/serve.d.ts +2 -0
- package/dist/cli/commands/serve.js +32 -0
- package/dist/cli/commands/start.d.ts +2 -0
- package/dist/cli/commands/start.js +32 -0
- package/dist/cli/commands/sync.d.ts +2 -0
- package/dist/cli/commands/sync.js +17 -0
- package/dist/cli/commands/uninstall.d.ts +2 -0
- package/dist/cli/commands/uninstall.js +39 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +114 -0
- package/dist/core/ConfigurationProvider.d.ts +31 -0
- package/dist/core/ConfigurationProvider.js +416 -0
- package/dist/core/InstallationService.d.ts +17 -0
- package/dist/core/InstallationService.js +144 -0
- package/dist/core/MCPManager.d.ts +17 -0
- package/dist/core/MCPManager.js +98 -0
- package/dist/core/RequirementService.d.ts +45 -0
- package/dist/core/RequirementService.js +123 -0
- package/dist/core/constants.d.ts +29 -0
- package/dist/core/constants.js +55 -0
- package/dist/core/installers/BaseInstaller.d.ts +73 -0
- package/dist/core/installers/BaseInstaller.js +247 -0
- package/dist/core/installers/ClientInstaller.d.ts +17 -0
- package/dist/core/installers/ClientInstaller.js +307 -0
- package/dist/core/installers/CommandInstaller.d.ts +36 -0
- package/dist/core/installers/CommandInstaller.js +170 -0
- package/dist/core/installers/GeneralInstaller.d.ts +32 -0
- package/dist/core/installers/GeneralInstaller.js +87 -0
- package/dist/core/installers/InstallerFactory.d.ts +52 -0
- package/dist/core/installers/InstallerFactory.js +95 -0
- package/dist/core/installers/NpmInstaller.d.ts +25 -0
- package/dist/core/installers/NpmInstaller.js +123 -0
- package/dist/core/installers/PipInstaller.d.ts +25 -0
- package/dist/core/installers/PipInstaller.js +114 -0
- package/dist/core/installers/RequirementInstaller.d.ts +32 -0
- package/dist/core/installers/RequirementInstaller.js +3 -0
- package/dist/core/installers/index.d.ts +6 -0
- package/dist/core/installers/index.js +7 -0
- package/dist/core/types.d.ts +152 -0
- package/dist/core/types.js +16 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +19 -0
- package/dist/services/InstallRequestValidator.d.ts +21 -0
- package/dist/services/InstallRequestValidator.js +99 -0
- package/dist/services/ServerService.d.ts +47 -0
- package/dist/services/ServerService.js +145 -0
- package/dist/utils/UpdateCheckTracker.d.ts +39 -0
- package/dist/utils/UpdateCheckTracker.js +80 -0
- package/dist/utils/clientUtils.d.ts +29 -0
- package/dist/utils/clientUtils.js +105 -0
- package/dist/utils/feedUtils.d.ts +5 -0
- package/dist/utils/feedUtils.js +29 -0
- package/dist/utils/githubAuth.d.ts +1 -0
- package/dist/utils/githubAuth.js +123 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.js +90 -0
- package/dist/utils/osUtils.d.ts +16 -0
- package/dist/utils/osUtils.js +235 -0
- package/dist/web/public/css/modal.css +250 -0
- package/dist/web/public/css/notifications.css +70 -0
- package/dist/web/public/index.html +157 -0
- package/dist/web/public/js/api.js +213 -0
- package/dist/web/public/js/modal.js +572 -0
- package/dist/web/public/js/notifications.js +99 -0
- package/dist/web/public/js/serverCategoryDetails.js +210 -0
- package/dist/web/public/js/serverCategoryList.js +82 -0
- package/dist/web/public/modal.html +61 -0
- package/dist/web/public/styles.css +155 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.js +150 -0
- package/package.json +53 -0
- package/src/cli/commands/install.ts +140 -0
- package/src/cli/commands/list.ts +112 -0
- package/src/cli/commands/pull.ts +16 -0
- package/src/cli/commands/serve.ts +37 -0
- package/src/cli/commands/uninstall.ts +54 -0
- package/src/cli/index.ts +127 -0
- package/src/core/ConfigurationProvider.ts +489 -0
- package/src/core/InstallationService.ts +173 -0
- package/src/core/MCPManager.ts +134 -0
- package/src/core/RequirementService.ts +147 -0
- package/src/core/constants.ts +61 -0
- package/src/core/installers/BaseInstaller.ts +292 -0
- package/src/core/installers/ClientInstaller.ts +423 -0
- package/src/core/installers/CommandInstaller.ts +185 -0
- package/src/core/installers/GeneralInstaller.ts +89 -0
- package/src/core/installers/InstallerFactory.ts +109 -0
- package/src/core/installers/NpmInstaller.ts +128 -0
- package/src/core/installers/PipInstaller.ts +121 -0
- package/src/core/installers/RequirementInstaller.ts +38 -0
- package/src/core/installers/index.ts +9 -0
- package/src/core/types.ts +163 -0
- package/src/index.ts +44 -0
- package/src/services/InstallRequestValidator.ts +112 -0
- package/src/services/ServerService.ts +181 -0
- package/src/utils/UpdateCheckTracker.ts +86 -0
- package/src/utils/clientUtils.ts +112 -0
- package/src/utils/feedUtils.ts +31 -0
- package/src/utils/githubAuth.ts +142 -0
- package/src/utils/logger.ts +101 -0
- package/src/utils/osUtils.ts +250 -0
- package/src/web/public/css/modal.css +250 -0
- package/src/web/public/css/notifications.css +70 -0
- package/src/web/public/index.html +157 -0
- package/src/web/public/js/api.js +213 -0
- package/src/web/public/js/modal.js +572 -0
- package/src/web/public/js/notifications.js +99 -0
- package/src/web/public/js/serverCategoryDetails.js +210 -0
- package/src/web/public/js/serverCategoryList.js +82 -0
- package/src/web/public/modal.html +61 -0
- package/src/web/public/styles.css +155 -0
- package/src/web/server.ts +195 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { allServerCategoriesData, fetchServerCategories } from './api.js';
|
|
2
|
+
import { showInstallModal } from './modal.js';
|
|
3
|
+
import { showToast, showConfirm } from './notifications.js';
|
|
4
|
+
|
|
5
|
+
const REFRESH_INTERVAL = 2000; // 2 seconds
|
|
6
|
+
let refreshTimer = null;
|
|
7
|
+
|
|
8
|
+
// Start refresh timer for installation status
|
|
9
|
+
function startRefreshTimer(serverName) {
|
|
10
|
+
// Clear existing timer if any
|
|
11
|
+
if (refreshTimer) {
|
|
12
|
+
clearInterval(refreshTimer);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Setup new refresh timer
|
|
16
|
+
refreshTimer = setInterval(async () => {
|
|
17
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
18
|
+
if (!server?.installationStatus?.serversStatus) return;
|
|
19
|
+
|
|
20
|
+
// Check if any installation is pending
|
|
21
|
+
const hasPendingInstallation = Object.values(server.installationStatus.serversStatus).some(serverStatus =>
|
|
22
|
+
Object.values(serverStatus.installedStatus || {}).some(status =>
|
|
23
|
+
status.status === 'pending' || status.status === 'in-progress'
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (hasPendingInstallation) {
|
|
28
|
+
await fetchServerCategories(); // Refresh data
|
|
29
|
+
await showServerDetails(serverName); // Update UI
|
|
30
|
+
} else {
|
|
31
|
+
clearInterval(refreshTimer); // Stop refreshing if no pending installations
|
|
32
|
+
}
|
|
33
|
+
}, REFRESH_INTERVAL);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Show server details
|
|
37
|
+
async function showServerDetails(serverName) {
|
|
38
|
+
console.log("Showing details for:", serverName);
|
|
39
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
40
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
41
|
+
|
|
42
|
+
if (!server) {
|
|
43
|
+
detailsDiv.innerHTML = '<p class="text-red-500">Error: Server data not found.</p>';
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Highlight selected server
|
|
48
|
+
document.querySelectorAll('.server-item').forEach(item => {
|
|
49
|
+
item.classList.remove('bg-blue-100', 'border-blue-300');
|
|
50
|
+
if (item.dataset.serverName === serverName) {
|
|
51
|
+
item.classList.add('bg-blue-100', 'border-blue-300');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Initial render with loading state
|
|
56
|
+
detailsDiv.innerHTML = `
|
|
57
|
+
<h3 class="text-xl font-semibold mb-2 text-gray-800">${server.displayName || server.name}</h3>
|
|
58
|
+
<p class="mb-4"><span class="font-semibold">Description:</span> ${server.description || 'N/A'}</p>
|
|
59
|
+
<div id="toolMcpsList" class="mt-4">
|
|
60
|
+
<div class="animate-pulse flex space-x-4">
|
|
61
|
+
<div class="flex-1 space-y-4 py-1">
|
|
62
|
+
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
|
|
63
|
+
<div class="space-y-2">
|
|
64
|
+
<div class="h-4 bg-gray-200 rounded"></div>
|
|
65
|
+
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
// Asynchronously load and render the servers list
|
|
73
|
+
try {
|
|
74
|
+
const serversListHtml = await renderServersList(server);
|
|
75
|
+
document.getElementById('toolMcpsList').innerHTML = serversListHtml;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('Error rendering servers list:', error);
|
|
78
|
+
document.getElementById('toolMcpsList').innerHTML = '<p class="text-red-500">Error loading server details.</p>';
|
|
79
|
+
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Start monitoring installation status
|
|
83
|
+
startRefreshTimer(serverName);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Render tools list
|
|
87
|
+
async function renderServersList(serverCategory) {
|
|
88
|
+
// Fetch available targets
|
|
89
|
+
const targetResponse = await fetch('/api/targets');
|
|
90
|
+
const targetData = await targetResponse.json();
|
|
91
|
+
const availableTargets = targetData.success ? targetData.data : [];
|
|
92
|
+
if (!serverCategory.feedConfiguration?.mcpServers) {
|
|
93
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const mcpServers = serverCategory.feedConfiguration.mcpServers;
|
|
97
|
+
if (mcpServers.length === 0) {
|
|
98
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let toolsHtml = `
|
|
102
|
+
<div class="flex justify-between items-center mb-4">
|
|
103
|
+
<h2 class="text-lg font-semibold text-gray-600">MCP Servers</h2>
|
|
104
|
+
</div>`;
|
|
105
|
+
|
|
106
|
+
mcpServers.forEach(mcpServer => {
|
|
107
|
+
const isInstalled = mcpServer.installed;
|
|
108
|
+
const envRequirements = mcpServer.installation?.['env:'] || mcpServer.installation?.env || {};
|
|
109
|
+
const hasEnvRequirements = Object.keys(envRequirements).length > 0;
|
|
110
|
+
|
|
111
|
+
toolsHtml += `
|
|
112
|
+
<div class="border border-gray-200 p-3 rounded mb-2 flex justify-between items-center hover:bg-gray-50 transition-all duration-150 ${!isInstalled ? 'bg-white' : 'bg-gray-50'}"
|
|
113
|
+
id="tool-item-${mcpServer.name}">
|
|
114
|
+
<div class="flex items-center flex-1">
|
|
115
|
+
<div>
|
|
116
|
+
<h5 class="font-semibold text-gray-800">${mcpServer.displayName || mcpServer.name}</h5>
|
|
117
|
+
<p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
|
|
118
|
+
<div class="flex flex-col">
|
|
119
|
+
<span class="text-xs font-semibold mb-2">Client Status:</span>
|
|
120
|
+
<div class="flex flex-wrap gap-2">
|
|
121
|
+
${availableTargets.map(client => {
|
|
122
|
+
const status = (serverCategory.installationStatus?.serversStatus[mcpServer.name]?.installedStatus|| {})[client];
|
|
123
|
+
const isInstalled = status?.status === 'completed';
|
|
124
|
+
return `
|
|
125
|
+
<span class="text-xs flex items-center ${isInstalled ? 'text-green-600 bg-green-50' : 'text-gray-600 bg-gray-50'} px-3 py-1 rounded-full shadow">
|
|
126
|
+
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
127
|
+
${isInstalled
|
|
128
|
+
? '<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>'
|
|
129
|
+
: '<path d="M7 3.5A1.5 1.5 0 018.5 2h3.879a1.5 1.5 0 011.06.44l3.122 3.12A1.5 1.5 0 0117 6.622V12.5a1.5 1.5 0 01-1.5 1.5h-1v-3.379a1.5 1.5 0 00-.44-1.06L10.94 6.44A1.5 1.5 0 009.879 6H7V3.5z M6 6h2.879A1.5 1.5 0 0110 7.5v1.379a1.5 1.5 0 01-.44 1.06L6.44 13.06A1.5 1.5 0 015.379 13H4.5A1.5 1.5 0 013 11.5V7.5A1.5 1.5 0 014.5 6H6z"></path>'
|
|
130
|
+
}
|
|
131
|
+
</svg>
|
|
132
|
+
${client}
|
|
133
|
+
</span>
|
|
134
|
+
`;
|
|
135
|
+
}).join('')}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
${hasEnvRequirements ? `<div class="mt-1 text-xs text-blue-600">
|
|
139
|
+
<svg class="w-3 h-3 inline mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
140
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
|
|
141
|
+
</svg>
|
|
142
|
+
Requires environment configuration
|
|
143
|
+
</div>` : ''}
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
${!isInstalled ? `
|
|
147
|
+
<button onclick="event.stopPropagation(); window.showInstallModal('${serverCategory.name}', '${mcpServer.name}')"
|
|
148
|
+
class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-3 rounded-full shadow-sm transition duration-150 ease-in-out">
|
|
149
|
+
Install
|
|
150
|
+
</button>
|
|
151
|
+
` : `
|
|
152
|
+
<div class="flex items-center gap-2">
|
|
153
|
+
<button onclick="event.stopPropagation(); window.uninstallTools('${serverCategory.name}', ['${mcpServer.name}'])"
|
|
154
|
+
class="bg-red-500 hover:bg-red-700 text-white text-sm font-bold py-1 px-3 rounded transition duration-150 ease-in-out">
|
|
155
|
+
Uninstall
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
158
|
+
`}
|
|
159
|
+
</div>
|
|
160
|
+
`;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return toolsHtml;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Uninstall tools
|
|
167
|
+
window.uninstallTools = async function(serverName, toolList) {
|
|
168
|
+
const confirmed = await showConfirm(`Are you sure you want to uninstall ${toolList.length} tool(s)?`);
|
|
169
|
+
if (!confirmed) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const response = await fetch(`/api/categories/${serverName}/uninstall`, {
|
|
175
|
+
method: 'POST',
|
|
176
|
+
headers: { 'Content-Type': 'application/json' },
|
|
177
|
+
body: JSON.stringify({ toolList })
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
const errorData = await response.text();
|
|
182
|
+
throw new Error(`Uninstallation failed: ${errorData || response.statusText}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const result = await response.json();
|
|
186
|
+
if (!result.success) {
|
|
187
|
+
throw new Error(result.error || 'Uninstallation failed');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
showToast('Tools uninstalled successfully!', 'success');
|
|
191
|
+
await fetchServerCategories(); // Refresh data
|
|
192
|
+
await showServerDetails(serverName); // Refresh UI
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error('Error uninstalling tools:', error);
|
|
195
|
+
showToast(`Error uninstalling tools: ${error.message}`, 'error');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Make showServerDetails available in window scope and handle async
|
|
200
|
+
window.showServerDetails = async function(serverName) {
|
|
201
|
+
try {
|
|
202
|
+
await showServerDetails(serverName);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('Error showing server details:', error);
|
|
205
|
+
document.getElementById('serverCategoryDetails').innerHTML = '<p class="text-red-500">Error loading server details.</p>';
|
|
206
|
+
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export { showServerDetails };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { allServerCategoriesData, fetchServerCategories } from './api.js';
|
|
2
|
+
import { showServerDetails } from './serverCategoryDetails.js';
|
|
3
|
+
import { showToast } from './notifications.js';
|
|
4
|
+
|
|
5
|
+
// Function to render server list (used by fetchServerCategories and search)
|
|
6
|
+
function renderServerCategoryList(servers) {
|
|
7
|
+
const serverCategoryList = document.getElementById('serverCategoryList');
|
|
8
|
+
|
|
9
|
+
if (servers.length === 0) {
|
|
10
|
+
serverCategoryList.innerHTML = '<p class="text-gray-500">No servers found matching search.</p>';
|
|
11
|
+
document.getElementById('serverCategoryDetails').innerHTML = '<p>Select a server from the list to see details.</p>'; // Clear details
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
serverCategoryList.innerHTML = servers.map(server => {
|
|
16
|
+
let statusHtml = '';
|
|
17
|
+
|
|
18
|
+
// Add tool status summary if available
|
|
19
|
+
if (server.installationStatus && server.installationStatus.serversStatus) {
|
|
20
|
+
const totalTools = Object.keys(server.installationStatus.serversStatus).length;
|
|
21
|
+
const installedTools = Object.values(server.installationStatus.serversStatus)
|
|
22
|
+
.filter(serverStatus =>
|
|
23
|
+
Object.values(serverStatus.installedStatus || {})
|
|
24
|
+
.some(opStatus => opStatus.status === 'completed' && opStatus.type === 'install')
|
|
25
|
+
).length;
|
|
26
|
+
|
|
27
|
+
if (totalTools > 0) {
|
|
28
|
+
let colorClass, icon, statusText;
|
|
29
|
+
|
|
30
|
+
if (installedTools === totalTools) {
|
|
31
|
+
// All tools installed
|
|
32
|
+
colorClass = "text-green-600 bg-green-50";
|
|
33
|
+
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="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg>';
|
|
34
|
+
statusText = "Fully Configured";
|
|
35
|
+
} else if (installedTools > 0) {
|
|
36
|
+
// Some tools installed
|
|
37
|
+
colorClass = "text-green-600 bg-green-50";
|
|
38
|
+
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="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg>';
|
|
39
|
+
statusText = "Partial Configured";
|
|
40
|
+
} else {
|
|
41
|
+
// No tools installed
|
|
42
|
+
colorClass = "text-red-600 bg-red-50";
|
|
43
|
+
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="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path></svg>';
|
|
44
|
+
statusText = "Not Configured";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
statusHtml = `<span class="${colorClass} inline-flex items-center px-2 py-1 rounded-full text-xs" style="width: fit-content; max-width: 100%;">
|
|
48
|
+
${icon}<span class="truncate">${statusText} (${installedTools}/${totalTools})</span>
|
|
49
|
+
</span>`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return `
|
|
54
|
+
<div class="server-item border border-gray-200 p-3 rounded hover:bg-gray-50 cursor-pointer transition duration-150 ease-in-out"
|
|
55
|
+
onclick="window.showServerDetails('${server.name}')"
|
|
56
|
+
data-server-name="${server.name}">
|
|
57
|
+
<h3 class="font-semibold text-gray-800">${server.displayName || server.name}</h3>
|
|
58
|
+
<p class="text-sm text-gray-500">${statusHtml}</p>
|
|
59
|
+
</div>
|
|
60
|
+
`;
|
|
61
|
+
}).join('');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Setup search functionality
|
|
65
|
+
function setupSearch() {
|
|
66
|
+
document.getElementById('searchBox').addEventListener('input', function () {
|
|
67
|
+
const searchTerm = this.value.toLowerCase();
|
|
68
|
+
|
|
69
|
+
// Filter the servers list based on search
|
|
70
|
+
if (allServerCategorisData && allServerCategorisData.length > 0) {
|
|
71
|
+
const filteredServers = allServerCategorisData.filter(server =>
|
|
72
|
+
(server.displayName || server.name).toLowerCase().includes(searchTerm) ||
|
|
73
|
+
(server.description || '').toLowerCase().includes(searchTerm)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
renderServerCategoryList(filteredServers);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Export functions
|
|
82
|
+
export { renderServerCategoryList, setupSearch };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<div id="installModal" class="modal">
|
|
2
|
+
<div class="modal-content">
|
|
3
|
+
<span class="close" onclick="closeModal()">×</span>
|
|
4
|
+
<div class="modal-header">
|
|
5
|
+
<h2 id="modalTitle" class="text-2xl font-bold text-gray-800"></h2>
|
|
6
|
+
<p class="text-gray-600 mt-2">Configure your installation settings below</p>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="modal-sections">
|
|
10
|
+
<!-- Requirements Section -->
|
|
11
|
+
<div class="section-container">
|
|
12
|
+
<div id="modalRequirements"></div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<!-- Client Status Section -->
|
|
16
|
+
<div class="section-container">
|
|
17
|
+
<div id="modalTargets" class="client-grid"></div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<!-- Environment Variables Section -->
|
|
21
|
+
<div class="section-container">
|
|
22
|
+
<div id="modalEnvInputs" class="space-y-4"></div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<form id="installForm" class="mt-8">
|
|
27
|
+
<div class="flex justify-end space-x-4">
|
|
28
|
+
<button type="button" onclick="closeModal()"
|
|
29
|
+
class="px-6 py-2.5 text-gray-600 hover:text-gray-800 font-medium rounded-lg hover:bg-gray-100 transition-colors">
|
|
30
|
+
Cancel
|
|
31
|
+
</button>
|
|
32
|
+
<button type="submit" class="submit-button">
|
|
33
|
+
Apply
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
</form>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- Loading Modal -->
|
|
41
|
+
<div id="installLoadingModal" class="modal" style="display:none; z-index:2000;">
|
|
42
|
+
<div class="modal-content" style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 340px; pointer-events:auto;">
|
|
43
|
+
<div style="width: 100%;">
|
|
44
|
+
<div style="display: flex; flex-direction: column; align-items: center; width: 100%;">
|
|
45
|
+
<div class="loading-icon" style="margin-bottom:8px;">
|
|
46
|
+
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" style="display: block; margin-left: auto; margin-right: auto;">
|
|
47
|
+
<circle cx="24" cy="24" r="20" stroke="#888" stroke-width="4" opacity="0.2"/>
|
|
48
|
+
<circle cx="24" cy="24" r="20" stroke="#3498db" stroke-width="4" stroke-linecap="round" stroke-dasharray="100" stroke-dashoffset="60">
|
|
49
|
+
<animateTransform attributeName="transform" type="rotate" from="0 24 24" to="360 24 24" dur="1s" repeatCount="indefinite"/>
|
|
50
|
+
</circle>
|
|
51
|
+
</svg>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="loading-title" style="font-size:1.5rem; font-weight:bold; margin-bottom:8px; text-align:center;">Installing...</div>
|
|
54
|
+
<div id="installLoadingMessage" style="min-height:48px; max-height:160px; overflow:auto; background:#f8f8f8; border-radius:6px; padding:12px; font-size:1rem; color:#444; text-align:left; width:100%;"></div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<link rel="stylesheet" href="/css/modal.css">
|
|
61
|
+
<link rel="stylesheet" href="/css/modal.css">
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/* Import Inter font */
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
|
3
|
+
|
|
4
|
+
/* Base styles */
|
|
5
|
+
body {
|
|
6
|
+
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* Enhanced modal styling */
|
|
10
|
+
.modal {
|
|
11
|
+
display: none;
|
|
12
|
+
position: fixed;
|
|
13
|
+
z-index: 50;
|
|
14
|
+
left: 0;
|
|
15
|
+
top: 0;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
overflow: auto;
|
|
19
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
20
|
+
backdrop-filter: blur(4px);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.modal-content {
|
|
24
|
+
background-color: #ffffff;
|
|
25
|
+
margin: 10% auto;
|
|
26
|
+
padding: 2rem;
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: 1rem;
|
|
29
|
+
width: 90%;
|
|
30
|
+
max-width: 500px;
|
|
31
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
32
|
+
transform: translateY(0);
|
|
33
|
+
transition: all 0.3s ease-out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.close-button {
|
|
37
|
+
color: #6b7280;
|
|
38
|
+
float: right;
|
|
39
|
+
font-size: 24px;
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
transition: color 0.2s ease;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.close-button:hover,
|
|
45
|
+
.close-button:focus {
|
|
46
|
+
color: #111827;
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Server list styles */
|
|
52
|
+
.server-list {
|
|
53
|
+
border-radius: 0.75rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.server-item {
|
|
57
|
+
padding: 0.75rem 1rem;
|
|
58
|
+
margin-bottom: 0.5rem;
|
|
59
|
+
border-radius: 0.5rem;
|
|
60
|
+
border: 1px solid #e5e7eb;
|
|
61
|
+
transition: all 0.2s ease;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.server-item:hover {
|
|
65
|
+
background-color: #f3f4f6;
|
|
66
|
+
transform: translateY(-1px);
|
|
67
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Tool card styles */
|
|
71
|
+
.tool-card {
|
|
72
|
+
border: 1px solid #e5e7eb;
|
|
73
|
+
border-radius: 0.75rem;
|
|
74
|
+
padding: 1.25rem;
|
|
75
|
+
margin-bottom: 1rem;
|
|
76
|
+
background-color: #ffffff;
|
|
77
|
+
transition: all 0.2s ease;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.tool-card:hover {
|
|
81
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Status badges */
|
|
85
|
+
.status-badge {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
padding: 0.25rem 0.75rem;
|
|
89
|
+
border-radius: 9999px;
|
|
90
|
+
font-size: 0.875rem;
|
|
91
|
+
font-weight: 500;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.status-badge.installed {
|
|
95
|
+
background-color: #dcfce7;
|
|
96
|
+
color: #166534;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.status-badge.not-installed {
|
|
100
|
+
background-color: #fee2e2;
|
|
101
|
+
color: #991b1b;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Button styles */
|
|
105
|
+
.btn {
|
|
106
|
+
display: inline-flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
padding: 0.5rem 1rem;
|
|
110
|
+
border-radius: 0.5rem;
|
|
111
|
+
font-weight: 500;
|
|
112
|
+
transition: all 0.2s ease;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.btn-install {
|
|
116
|
+
background-color: #2563eb;
|
|
117
|
+
color: white;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.btn-install:hover {
|
|
121
|
+
background-color: #1d4ed8;
|
|
122
|
+
transform: translateY(-1px);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.btn-uninstall {
|
|
126
|
+
background-color: #dc2626;
|
|
127
|
+
color: white;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.btn-uninstall:hover {
|
|
131
|
+
background-color: #b91c1c;
|
|
132
|
+
transform: translateY(-1px);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Icon styles */
|
|
136
|
+
.icon {
|
|
137
|
+
width: 1.25rem;
|
|
138
|
+
height: 1.25rem;
|
|
139
|
+
margin-right: 0.5rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Input styles */
|
|
143
|
+
.search-input {
|
|
144
|
+
width: 100%;
|
|
145
|
+
padding: 0.75rem 1rem 0.75rem 2.5rem;
|
|
146
|
+
border: 1px solid #e5e7eb;
|
|
147
|
+
border-radius: 0.5rem;
|
|
148
|
+
transition: all 0.2s ease;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.search-input:focus {
|
|
152
|
+
outline: none;
|
|
153
|
+
border-color: #2563eb;
|
|
154
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
155
|
+
}
|