Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 104 additions & 14 deletions mcpgateway/static/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8166,53 +8166,143 @@ function setupSelectorSearch() {
const searchTools = safeGetElement("searchTools", true);
if (searchTools) {
searchTools.addEventListener("input", function () {
filterItems(this.value, ".tool-item", ["span"]);
filterSelectorItems(
this.value,
"#associatedTools",
".tool-item",
"noToolsMessage",
"searchQuery",
);
});
}

// Resources search
const searchResources = safeGetElement("searchResources", true);
if (searchResources) {
searchResources.addEventListener("input", function () {
filterItems(this.value, ".resource-item", ["span", ".text-xs"]);
filterSelectorItems(
this.value,
"#associatedResources",
".resource-item",
"noResourcesMessage",
"searchResourcesQuery",
);
});
}

// Prompts search
const searchPrompts = safeGetElement("searchPrompts", true);
if (searchPrompts) {
searchPrompts.addEventListener("input", function () {
filterItems(this.value, ".prompt-item", ["span", ".text-xs"]);
filterSelectorItems(
this.value,
"#associatedPrompts",
".prompt-item",
"noPromptsMessage",
"searchPromptsQuery",
);
});
}
}

/**
* Generic function to filter items in multi-select dropdowns
* Generic function to filter items in multi-select dropdowns with no results message
*/
function filterItems(searchText, itemSelector, textSelectors) {
const items = document.querySelectorAll(itemSelector);
const search = searchText.toLowerCase();
function filterSelectorItems(
searchText,
containerSelector,
itemSelector,
noResultsId,
searchQueryId,
) {
const container = document.querySelector(containerSelector);
if (!container) {
return;
}

const items = container.querySelectorAll(itemSelector);
const search = searchText.toLowerCase().trim();
let hasVisibleItems = false;

items.forEach((item) => {
let textContent = "";

// Collect text from all specified selectors within the item
textSelectors.forEach((selector) => {
const elements = item.querySelectorAll(selector);
elements.forEach((el) => {
textContent += " " + el.textContent;
});
// Get text from all text nodes within the item
const textElements = item.querySelectorAll(
"span, .text-xs, .font-medium",
);
textElements.forEach((el) => {
textContent += " " + el.textContent;
});

if (textContent.toLowerCase().includes(search)) {
// Also get direct text content
textContent += " " + item.textContent;

if (search === "" || textContent.toLowerCase().includes(search)) {
item.style.display = "";
hasVisibleItems = true;
} else {
item.style.display = "none";
}
});

// Handle no results message
const noResultsMessage = safeGetElement(noResultsId, true);
const searchQuerySpan = safeGetElement(searchQueryId, true);

if (search !== "" && !hasVisibleItems) {
if (noResultsMessage) {
noResultsMessage.style.display = "block";
}
if (searchQuerySpan) {
searchQuerySpan.textContent = searchText;
}
} else {
if (noResultsMessage) {
noResultsMessage.style.display = "none";
}
}
}

/**
* Filter server table rows based on search text
*/
function filterServerTable(searchText) {
try {
const tbody = document.querySelector(
'tbody[data-testid="server-list"]',
);
if (!tbody) {
console.warn("Server table not found");
return;
}

const rows = tbody.querySelectorAll('tr[data-testid="server-item"]');
const search = searchText.toLowerCase().trim();

rows.forEach((row) => {
let textContent = "";

// Get text from all cells in the row
const cells = row.querySelectorAll("td");
cells.forEach((cell) => {
textContent += " " + cell.textContent;
});

if (search === "" || textContent.toLowerCase().includes(search)) {
row.style.display = "";
} else {
row.style.display = "none";
}
});
} catch (error) {
console.error("Error filtering server table:", error);
}
}

// Make server search function available globally
window.filterServerTable = filterServerTable;

function handleAuthTypeChange() {
const authType = this.value;
const basicFields = safeGetElement("auth-basic-fields-gw");
Expand Down
43 changes: 16 additions & 27 deletions mcpgateway/templates/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -1081,9 +1081,11 @@ <h2 class="text-2xl font-bold dark:text-gray-200">
<div class="flex items-center space-x-4">
<input
type="text"
id="search-servers"
data-testid="search-input"
placeholder="Search servers..."
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
oninput="filterServerTable(this.value)"
/>
<div class="flex items-center">
<input
Expand Down Expand Up @@ -1584,6 +1586,13 @@ <h3 class="text-lg font-bold mb-4 dark:text-gray-200">
</div>
</label>
{% endfor %}
<p
id="noResourcesMessage"
class="text-gray-700 dark:text-gray-300"
style="display: none"
>
No resource found containing "<span id="searchResourcesQuery"></span>"
</p>
</div>
<div class="flex justify-end gap-3 mt-3">
<button
Expand Down Expand Up @@ -1643,6 +1652,13 @@ <h3 class="text-lg font-bold mb-4 dark:text-gray-200">
</div>
</label>
{% endfor %}
<p
id="noPromptsMessage"
class="text-gray-700 dark:text-gray-300"
style="display: none"
>
No prompt found containing "<span id="searchPromptsQuery"></span>"
</p>
</div>
<div class="flex justify-end gap-3 mt-3">
<button
Expand Down Expand Up @@ -7904,34 +7920,7 @@ <h4>Breakdown by Type:</h4>
});

// Add search functionality for filtering tools
document.addEventListener('DOMContentLoaded', function() {
const searchBox = document.getElementById('searchTools');
const toolItems = document.querySelectorAll('#associatedTools .tool-item');
const noToolsMessage = document.getElementById('noToolsMessage');
const searchQuerySpan = document.getElementById('searchQuery');

searchBox.addEventListener('input', function() {
const filter = this.value.toLowerCase();
let hasVisibleItems = false;

toolItems.forEach(function(toolItem) {
const toolName = toolItem.querySelector('span').textContent.toLowerCase();
if (toolName.includes(filter)) {
toolItem.style.display = '';
hasVisibleItems = true;
} else {
toolItem.style.display = 'none';
}
});

if (hasVisibleItems) {
noToolsMessage.style.display = 'none';
} else {
searchQuerySpan.textContent = filter;
noToolsMessage.style.display = 'block';
}
});
});
</script>
<script>
function handleEditIntegrationTypeChange() {
Expand Down
Loading