@@ -148,30 +148,43 @@ document.addEventListener("DOMContentLoaded", function () {
148
148
} ) ;
149
149
150
150
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
+ }
159
177
} )
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
+
175
188
176
189
document
177
190
. getElementById ( "add-resource-form" )
@@ -318,7 +331,7 @@ document.addEventListener("DOMContentLoaded", function () {
318
331
) ;
319
332
320
333
const requestTypeMap = {
321
- MCP : [ "SSE" , "STDIO" ] ,
334
+ MCP : [ "SSE" , "STREAMABLE" , " STDIO"] ,
322
335
REST : [ "GET" , "POST" , "PUT" , "DELETE" ] ,
323
336
} ;
324
337
@@ -377,16 +390,16 @@ function showTab(tabName) {
377
390
panel . classList . add ( "hidden" ) ;
378
391
} ) ;
379
392
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" ) ;
382
395
} ) ;
383
396
document . getElementById ( `${ tabName } -panel` ) . classList . remove ( "hidden" ) ;
384
397
document
385
398
. 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" ) ;
387
400
document
388
401
. querySelector ( `[href="#${ tabName } "]` )
389
- . classList . remove ( "border-transparent" , "text-gray-500" ) ;
402
+ . classList . remove ( "border-transparent" , "text-gray-500" , "dark:text-gray-400" ) ;
390
403
391
404
if ( tabName === "metrics" ) {
392
405
loadAggregatedMetrics ( ) ;
@@ -896,6 +909,10 @@ async function viewGateway(gatewayId) {
896
909
<p><strong>Name:</strong> ${ gateway . name } </p>
897
910
<p><strong>URL:</strong> ${ gateway . url } </p>
898
911
<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>
899
916
<p><strong>Status:</strong>
900
917
<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" } ">
901
918
${ gateway . isActive ? "Active" : "Inactive" }
@@ -927,6 +944,7 @@ async function editGateway(gatewayId) {
927
944
document . getElementById ( "edit-gateway-url" ) . value = gateway . url ;
928
945
document . getElementById ( "edit-gateway-description" ) . value =
929
946
gateway . description || "" ;
947
+ document . getElementById ( "edit-gateway-transport" ) . value = gateway . transport ;
930
948
openModal ( "gateway-edit-modal" ) ;
931
949
} catch ( error ) {
932
950
console . error ( "Error fetching gateway details:" , error ) ;
@@ -1310,64 +1328,64 @@ async function loadAggregatedMetrics() {
1310
1328
1311
1329
// Build an aggregated metrics table
1312
1330
const tableHTML = `
1313
- <table class="min-w-full bg-white border">
1331
+ <table class="min-w-full bg-white border dark:bg-gray-900 ">
1314
1332
<thead>
1315
1333
<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>
1325
1343
</tr>
1326
1344
</thead>
1327
1345
<tbody>
1328
1346
<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>
1338
1356
</tr>
1339
1357
<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>
1349
1367
</tr>
1350
1368
<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>
1360
1378
</tr>
1361
1379
<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>
1371
1389
</tr>
1372
1390
</tbody>
1373
1391
</table>
@@ -1437,9 +1455,9 @@ async function loadTopTools() {
1437
1455
let html = `<table class="min-w-full border">
1438
1456
<thead>
1439
1457
<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>
1443
1461
</tr>
1444
1462
</thead>
1445
1463
<tbody>` ;
@@ -1473,10 +1491,10 @@ async function loadTopResources() {
1473
1491
let html = `<table class="min-w-full border">
1474
1492
<thead>
1475
1493
<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>
1480
1498
</tr>
1481
1499
</thead>
1482
1500
<tbody>` ;
@@ -1511,9 +1529,9 @@ async function loadTopServers() {
1511
1529
let html = `<table class="min-w-full border">
1512
1530
<thead>
1513
1531
<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>
1517
1535
</tr>
1518
1536
</thead>
1519
1537
<tbody>` ;
@@ -1547,9 +1565,9 @@ async function loadTopPrompts() {
1547
1565
let html = `<table class="min-w-full border">
1548
1566
<thead>
1549
1567
<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>
1553
1571
</tr>
1554
1572
</thead>
1555
1573
<tbody>` ;
@@ -1645,9 +1663,9 @@ async function runToolTest() {
1645
1663
const formData = new FormData ( form ) ;
1646
1664
const params = { } ;
1647
1665
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" ;
1651
1669
} else {
1652
1670
params [ key ] = value ;
1653
1671
}
@@ -1656,46 +1674,47 @@ async function runToolTest() {
1656
1674
}
1657
1675
}
1658
1676
1659
- // Build the JSON-RPC payload using the tool's name as the method
1660
1677
const payload = {
1661
1678
jsonrpc : "2.0" ,
1662
1679
id : Date . now ( ) ,
1663
1680
method : currentTestTool . name ,
1664
1681
params : params ,
1665
1682
} ;
1666
1683
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" ,
1696
1698
} ) ;
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
+ }
1697
1715
}
1698
1716
1717
+
1699
1718
/* ---------------------------------------------------------------
1700
1719
* Utility: copy a JSON string (or any text) to the system clipboard
1701
1720
* ------------------------------------------------------------- */
@@ -1753,7 +1772,7 @@ function closeModal(modalId, clearId=null) {
1753
1772
}
1754
1773
1755
1774
const integrationRequestMap = {
1756
- MCP : [ "SSE" , "STDIO" ] ,
1775
+ MCP : [ "SSE" , "STREAMABLE" , " STDIO"] ,
1757
1776
REST : [ "GET" , "POST" , "PUT" , "DELETE" ] ,
1758
1777
} ;
1759
1778
0 commit comments