Skip to content

Commit acea5b5

Browse files
committed
Dark Mode applied for elements across the web tool & changed format for version info panel to fit all information and json within the box
Signed-off-by: Abdul Samad <[email protected]>
1 parent 17bb99c commit acea5b5

File tree

3 files changed

+444
-379
lines changed

3 files changed

+444
-379
lines changed

mcpgateway/static/admin.js

Lines changed: 140 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -148,30 +148,43 @@ document.addEventListener("DOMContentLoaded", function () {
148148
});
149149

150150
document
151-
.getElementById("add-gateway-form")
152-
.addEventListener("submit", (e) => {
153-
e.preventDefault();
154-
const form = e.target;
155-
const formData = new FormData(form);
156-
fetch(`${window.ROOT_PATH}/admin/gateways`, {
157-
method: "POST",
158-
body: formData,
151+
.getElementById("add-gateway-form")
152+
.addEventListener("submit", (e) => {
153+
e.preventDefault();
154+
155+
const form = e.target;
156+
const formData = new FormData(form);
157+
158+
const status = document.getElementById("status-gateways");
159+
const loading = document.getElementById("add-gateway-loading");
160+
161+
// Show loading and clear previous status
162+
loading.style.display = "block";
163+
status.textContent = "";
164+
status.classList.remove("error-status");
165+
166+
fetch(`${window.ROOT_PATH}/admin/gateways`, {
167+
method: "POST",
168+
body: formData,
169+
})
170+
.then((response) => {
171+
if (!response.ok) {
172+
status.textContent = "Connection failed!";
173+
status.classList.add("error-status");
174+
} else {
175+
location.reload(); // Will exit before hiding spinner
176+
}
159177
})
160-
.then((response) => {
161-
console.log(response);
162-
if (!response.ok) {
163-
const status = document.getElementById("status-gateways");
164-
status.textContent = "Connection failed!";
165-
status.classList.add("error-status");
166-
} else {
167-
location.reload();
168-
console.log(response);
169-
}
170-
})
171-
.catch((error) => {
172-
console.error("Error:", error);
173-
});
174-
});
178+
.catch((error) => {
179+
console.error("Error:", error);
180+
status.textContent = "An error occurred!";
181+
status.classList.add("error-status");
182+
})
183+
.finally(() => {
184+
loading.style.display = "none"; // Hide loading
185+
});
186+
});
187+
175188

176189
document
177190
.getElementById("add-resource-form")
@@ -318,7 +331,7 @@ document.addEventListener("DOMContentLoaded", function () {
318331
);
319332

320333
const requestTypeMap = {
321-
MCP: ["SSE", "STDIO"],
334+
MCP: ["SSE", "STREAMABLE", "STDIO"],
322335
REST: ["GET", "POST", "PUT", "DELETE"],
323336
};
324337

@@ -377,16 +390,16 @@ function showTab(tabName) {
377390
panel.classList.add("hidden");
378391
});
379392
document.querySelectorAll(".tab-link").forEach((link) => {
380-
link.classList.remove("border-indigo-500", "text-indigo-600");
381-
link.classList.add("border-transparent", "text-gray-500");
393+
link.classList.remove("border-indigo-500", "text-indigo-600", "dark:text-indigo-500", "dark:border-indigo-400");
394+
link.classList.add("border-transparent", "text-gray-500", "dark:text-gray-400");
382395
});
383396
document.getElementById(`${tabName}-panel`).classList.remove("hidden");
384397
document
385398
.querySelector(`[href="#${tabName}"]`)
386-
.classList.add("border-indigo-500", "text-indigo-600");
399+
.classList.add("border-indigo-500", "text-indigo-600", "dark:text-indigo-500", "dark:border-indigo-400");
387400
document
388401
.querySelector(`[href="#${tabName}"]`)
389-
.classList.remove("border-transparent", "text-gray-500");
402+
.classList.remove("border-transparent", "text-gray-500", "dark:text-gray-400");
390403

391404
if (tabName === "metrics") {
392405
loadAggregatedMetrics();
@@ -896,6 +909,10 @@ async function viewGateway(gatewayId) {
896909
<p><strong>Name:</strong> ${gateway.name}</p>
897910
<p><strong>URL:</strong> ${gateway.url}</p>
898911
<p><strong>Description:</strong> ${gateway.description || "N/A"}</p>
912+
<p><strong>Transport:</strong>
913+
${gateway.transport === "STREAMABLEHTTP" ? "Streamable HTTP" :
914+
gateway.transport === "SSE" ? "SSE" : "N/A"}
915+
</p>
899916
<p><strong>Status:</strong>
900917
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${gateway.isActive ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}">
901918
${gateway.isActive ? "Active" : "Inactive"}
@@ -927,6 +944,7 @@ async function editGateway(gatewayId) {
927944
document.getElementById("edit-gateway-url").value = gateway.url;
928945
document.getElementById("edit-gateway-description").value =
929946
gateway.description || "";
947+
document.getElementById("edit-gateway-transport").value = gateway.transport;
930948
openModal("gateway-edit-modal");
931949
} catch (error) {
932950
console.error("Error fetching gateway details:", error);
@@ -1310,64 +1328,64 @@ async function loadAggregatedMetrics() {
13101328

13111329
// Build an aggregated metrics table
13121330
const tableHTML = `
1313-
<table class="min-w-full bg-white border">
1331+
<table class="min-w-full bg-white border dark:bg-gray-900">
13141332
<thead>
13151333
<tr>
1316-
<th class="py-2 px-4 border">Entity</th>
1317-
<th class="py-2 px-4 border">Total</th>
1318-
<th class="py-2 px-4 border">Successful</th>
1319-
<th class="py-2 px-4 border">Failed</th>
1320-
<th class="py-2 px-4 border">Failure Rate</th>
1321-
<th class="py-2 px-4 border">Min RT</th>
1322-
<th class="py-2 px-4 border">Max RT</th>
1323-
<th class="py-2 px-4 border">Avg RT</th>
1324-
<th class="py-2 px-4 border">Last Exec</th>
1334+
<th class="py-2 px-4 border dark:text-gray-200">Entity</th>
1335+
<th class="py-2 px-4 border dark:text-gray-200">Total</th>
1336+
<th class="py-2 px-4 border dark:text-gray-200">Successful</th>
1337+
<th class="py-2 px-4 border dark:text-gray-200">Failed</th>
1338+
<th class="py-2 px-4 border dark:text-gray-200">Failure Rate</th>
1339+
<th class="py-2 px-4 border dark:text-gray-200">Min RT</th>
1340+
<th class="py-2 px-4 border dark:text-gray-200">Max RT</th>
1341+
<th class="py-2 px-4 border dark:text-gray-200">Avg RT</th>
1342+
<th class="py-2 px-4 border dark:text-gray-200">Last Exec</th>
13251343
</tr>
13261344
</thead>
13271345
<tbody>
13281346
<tr>
1329-
<td class="py-2 px-4 border font-semibold">Tools</td>
1330-
<td class="py-2 px-4 border">${toolsTotal}</td>
1331-
<td class="py-2 px-4 border">${toolsSuccess}</td>
1332-
<td class="py-2 px-4 border">${toolsFailed}</td>
1333-
<td class="py-2 px-4 border">${toolsFailureRate}</td>
1334-
<td class="py-2 px-4 border">${toolsMin}</td>
1335-
<td class="py-2 px-4 border">${toolsMax}</td>
1336-
<td class="py-2 px-4 border">${toolsAvg}</td>
1337-
<td class="py-2 px-4 border">${toolsLast}</td>
1347+
<td class="py-2 px-4 border font-semibold dark:text-gray-200">Tools</td>
1348+
<td class="py-2 px-4 border dark:text-gray-300">${toolsTotal}</td>
1349+
<td class="py-2 px-4 border dark:text-gray-300">${toolsSuccess}</td>
1350+
<td class="py-2 px-4 border dark:text-gray-300">${toolsFailed}</td>
1351+
<td class="py-2 px-4 border dark:text-gray-300">${toolsFailureRate}</td>
1352+
<td class="py-2 px-4 border dark:text-gray-300">${toolsMin}</td>
1353+
<td class="py-2 px-4 border dark:text-gray-300">${toolsMax}</td>
1354+
<td class="py-2 px-4 border dark:text-gray-300">${toolsAvg}</td>
1355+
<td class="py-2 px-4 border dark:text-gray-300">${toolsLast}</td>
13381356
</tr>
13391357
<tr>
1340-
<td class="py-2 px-4 border font-semibold">Resources</td>
1341-
<td class="py-2 px-4 border">${resourcesTotal}</td>
1342-
<td class="py-2 px-4 border">${resourcesSuccess}</td>
1343-
<td class="py-2 px-4 border">${resourcesFailed}</td>
1344-
<td class="py-2 px-4 border">${resourcesFailureRate}</td>
1345-
<td class="py-2 px-4 border">${resourcesMin}</td>
1346-
<td class="py-2 px-4 border">${resourcesMax}</td>
1347-
<td class="py-2 px-4 border">${resourcesAvg}</td>
1348-
<td class="py-2 px-4 border">${resourcesLast}</td>
1358+
<td class="py-2 px-4 border font-semibold dark:text-gray-200">Resources</td>
1359+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesTotal}</td>
1360+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesSuccess}</td>
1361+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesFailed}</td>
1362+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesFailureRate}</td>
1363+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesMin}</td>
1364+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesMax}</td>
1365+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesAvg}</td>
1366+
<td class="py-2 px-4 border dark:text-gray-300">${resourcesLast}</td>
13491367
</tr>
13501368
<tr>
1351-
<td class="py-2 px-4 border font-semibold">Servers</td>
1352-
<td class="py-2 px-4 border">${serversTotal}</td>
1353-
<td class="py-2 px-4 border">${serversSuccess}</td>
1354-
<td class="py-2 px-4 border">${serversFailed}</td>
1355-
<td class="py-2 px-4 border">${serversFailureRate}</td>
1356-
<td class="py-2 px-4 border">${serversMin}</td>
1357-
<td class="py-2 px-4 border">${serversMax}</td>
1358-
<td class="py-2 px-4 border">${serversAvg}</td>
1359-
<td class="py-2 px-4 border">${serversLast}</td>
1369+
<td class="py-2 px-4 border font-semibold dark:text-gray-200">Servers</td>
1370+
<td class="py-2 px-4 border dark:text-gray-300">${serversTotal}</td>
1371+
<td class="py-2 px-4 border dark:text-gray-300">${serversSuccess}</td>
1372+
<td class="py-2 px-4 border dark:text-gray-300">${serversFailed}</td>
1373+
<td class="py-2 px-4 border dark:text-gray-300">${serversFailureRate}</td>
1374+
<td class="py-2 px-4 border dark:text-gray-300">${serversMin}</td>
1375+
<td class="py-2 px-4 border dark:text-gray-300">${serversMax}</td>
1376+
<td class="py-2 px-4 border dark:text-gray-300">${serversAvg}</td>
1377+
<td class="py-2 px-4 border dark:text-gray-300">${serversLast}</td>
13601378
</tr>
13611379
<tr>
1362-
<td class="py-2 px-4 border font-semibold">Prompts</td>
1363-
<td class="py-2 px-4 border">${promptsTotal}</td>
1364-
<td class="py-2 px-4 border">${promptsSuccess}</td>
1365-
<td class="py-2 px-4 border">${promptsFailed}</td>
1366-
<td class="py-2 px-4 border">${promptsFailureRate}</td>
1367-
<td class="py-2 px-4 border">${promptsMin}</td>
1368-
<td class="py-2 px-4 border">${promptsMax}</td>
1369-
<td class="py-2 px-4 border">${promptsAvg}</td>
1370-
<td class="py-2 px-4 border">${promptsLast}</td>
1380+
<td class="py-2 px-4 border font-semibold dark:text-gray-200">Prompts</td>
1381+
<td class="py-2 px-4 border dark:text-gray-300">${promptsTotal}</td>
1382+
<td class="py-2 px-4 border dark:text-gray-300">${promptsSuccess}</td>
1383+
<td class="py-2 px-4 border dark:text-gray-300">${promptsFailed}</td>
1384+
<td class="py-2 px-4 border dark:text-gray-300">${promptsFailureRate}</td>
1385+
<td class="py-2 px-4 border dark:text-gray-300">${promptsMin}</td>
1386+
<td class="py-2 px-4 border dark:text-gray-300">${promptsMax}</td>
1387+
<td class="py-2 px-4 border dark:text-gray-300">${promptsAvg}</td>
1388+
<td class="py-2 px-4 border dark:text-gray-300">${promptsLast}</td>
13711389
</tr>
13721390
</tbody>
13731391
</table>
@@ -1437,9 +1455,9 @@ async function loadTopTools() {
14371455
let html = `<table class="min-w-full border">
14381456
<thead>
14391457
<tr>
1440-
<th class="py-1 px-2 border">ID</th>
1441-
<th class="py-1 px-2 border">Name</th>
1442-
<th class="py-1 px-2 border">Executions</th>
1458+
<th class="py-1 px-2 border dark:text-gray-300">ID</th>
1459+
<th class="py-1 px-2 border dark:text-gray-300">Name</th>
1460+
<th class="py-1 px-2 border dark:text-gray-300">Executions</th>
14431461
</tr>
14441462
</thead>
14451463
<tbody>`;
@@ -1473,10 +1491,10 @@ async function loadTopResources() {
14731491
let html = `<table class="min-w-full border">
14741492
<thead>
14751493
<tr>
1476-
<th class="py-1 px-2 border">ID</th>
1477-
<th class="py-1 px-2 border">URI</th>
1478-
<th class="py-1 px-2 border">Name</th>
1479-
<th class="py-1 px-2 border">Executions</th>
1494+
<th class="py-1 px-2 border dark:text-gray-300">ID</th>
1495+
<th class="py-1 px-2 border dark:text-gray-300">URI</th>
1496+
<th class="py-1 px-2 border dark:text-gray-300">Name</th>
1497+
<th class="py-1 px-2 border dark:text-gray-300">Executions</th>
14801498
</tr>
14811499
</thead>
14821500
<tbody>`;
@@ -1511,9 +1529,9 @@ async function loadTopServers() {
15111529
let html = `<table class="min-w-full border">
15121530
<thead>
15131531
<tr>
1514-
<th class="py-1 px-2 border">ID</th>
1515-
<th class="py-1 px-2 border">Name</th>
1516-
<th class="py-1 px-2 border">Executions</th>
1532+
<th class="py-1 px-2 border dark:text-gray-300">ID</th>
1533+
<th class="py-1 px-2 border dark:text-gray-300">Name</th>
1534+
<th class="py-1 px-2 border dark:text-gray-300">Executions</th>
15171535
</tr>
15181536
</thead>
15191537
<tbody>`;
@@ -1547,9 +1565,9 @@ async function loadTopPrompts() {
15471565
let html = `<table class="min-w-full border">
15481566
<thead>
15491567
<tr>
1550-
<th class="py-1 px-2 border">ID</th>
1551-
<th class="py-1 px-2 border">Name</th>
1552-
<th class="py-1 px-2 border">Executions</th>
1568+
<th class="py-1 px-2 border dark:text-gray-300">ID</th>
1569+
<th class="py-1 px-2 border dark:text-gray-300">Name</th>
1570+
<th class="py-1 px-2 border dark:text-gray-300">Executions</th>
15531571
</tr>
15541572
</thead>
15551573
<tbody>`;
@@ -1645,9 +1663,9 @@ async function runToolTest() {
16451663
const formData = new FormData(form);
16461664
const params = {};
16471665
for (const [key, value] of formData.entries()) {
1648-
if(isNaN(value)) {
1649-
if(value.toLowerCase() === "true" || value.toLowerCase() === "false") {
1650-
params[key] = Boolean(value.toLowerCase() === "true");
1666+
if (isNaN(value)) {
1667+
if (value.toLowerCase() === "true" || value.toLowerCase() === "false") {
1668+
params[key] = value.toLowerCase() === "true";
16511669
} else {
16521670
params[key] = value;
16531671
}
@@ -1656,46 +1674,47 @@ async function runToolTest() {
16561674
}
16571675
}
16581676

1659-
// Build the JSON-RPC payload using the tool's name as the method
16601677
const payload = {
16611678
jsonrpc: "2.0",
16621679
id: Date.now(),
16631680
method: currentTestTool.name,
16641681
params: params,
16651682
};
16661683

1667-
// Send the request to your /rpc endpoint
1668-
fetch(`${window.ROOT_PATH}/rpc`, {
1669-
method: "POST",
1670-
headers: {
1671-
"Content-Type": "application/json", // ← make sure we include this
1672-
},
1673-
body: JSON.stringify(payload),
1674-
credentials: "include",
1675-
})
1676-
.then((response) => response.json())
1677-
.then((result) => {
1678-
const resultStr = JSON.stringify(result, null, 2);
1679-
1680-
const container = document.getElementById("tool-test-result");
1681-
container.innerHTML = ''; // clear any old editor
1682-
1683-
toolTestResultEditor = window.CodeMirror(
1684-
document.getElementById("tool-test-result"),
1685-
{
1686-
value: resultStr,
1687-
mode: "application/json",
1688-
theme: "monokai",
1689-
readOnly: true,
1690-
lineNumbers: true,
1691-
},
1692-
);
1693-
})
1694-
.catch((error) => {
1695-
document.getElementById("tool-test-result").innerText = "Error: " + error;
1684+
// Show loading
1685+
const loadingElement = document.getElementById("tool-test-loading");
1686+
loadingElement.style.display = "block";
1687+
const resultContainer = document.getElementById("tool-test-result");
1688+
resultContainer.innerHTML = "";
1689+
1690+
try {
1691+
const response = await fetch(`${window.ROOT_PATH}/rpc`, {
1692+
method: "POST",
1693+
headers: {
1694+
"Content-Type": "application/json",
1695+
},
1696+
body: JSON.stringify(payload),
1697+
credentials: "include",
16961698
});
1699+
1700+
const result = await response.json();
1701+
const resultStr = JSON.stringify(result, null, 2);
1702+
1703+
toolTestResultEditor = window.CodeMirror(resultContainer, {
1704+
value: resultStr,
1705+
mode: "application/json",
1706+
theme: "monokai",
1707+
readOnly: true,
1708+
lineNumbers: true,
1709+
});
1710+
} catch (error) {
1711+
resultContainer.innerText = "Error: " + error;
1712+
} finally {
1713+
loadingElement.style.display = "none"; // Hide loading after fetch or error
1714+
}
16971715
}
16981716

1717+
16991718
/* ---------------------------------------------------------------
17001719
* Utility: copy a JSON string (or any text) to the system clipboard
17011720
* ------------------------------------------------------------- */
@@ -1753,7 +1772,7 @@ function closeModal(modalId, clearId=null) {
17531772
}
17541773

17551774
const integrationRequestMap = {
1756-
MCP: ["SSE", "STDIO"],
1775+
MCP: ["SSE", "STREAMABLE", "STDIO"],
17571776
REST: ["GET", "POST", "PUT", "DELETE"],
17581777
};
17591778

0 commit comments

Comments
 (0)