Skip to content

[BUG][UI]: Arrow key pagination shortcuts always target the first pagination control on the pageย #3040

@marekdano

Description

@marekdano

๐Ÿž Bug Summary

The keyboard navigation shortcuts for pagination (โ† / โ†’ arrow keys) always target the first pagination control found in the DOM, regardless of which tab or section the user is currently viewing.

This happens because the keydown handler in admin.js uses document.querySelector(), which returns the first matching element in DOM order:

  const prevBtn = document.querySelector('[\\@click="prevPage()"]');
  const nextBtn = document.querySelector('[\\@click="nextPage()"]');

If the page has multiple pagination controls (e.g. MCP Gateways, Virtual Servers, Tools), pressing โ†’ will always paginate the first section (e.g. MCP Gateways) even if the user is viewing the Tools tab.


๐Ÿงฉ Affected Component

Select the area of the project impacted:

  • mcpgateway - API
  • mcpgateway - UI (admin panel)
  • mcpgateway.wrapper - stdio wrapper
  • Federation or Transports
  • CLI, Makefiles, or shell scripts
  • Container setup (Docker/Podman/Compose)
  • Other (explain below)

๐Ÿ” Steps to Reproduce

  1. Open the Admin UI
  2. Navigate to a tab that is not the first one (e.g. Tools)
  3. Press โ†’ arrow key to go to the next page
  4. Observe that the first tab's table Gateways/Virtual Servers paginates, but no action is taken on the Tools table

Note: Also pressing on โ†’ arrow key, we go from page 1 to the last one.

๐Ÿค” Expected Behavior

Arrow key shortcuts should paginate the table in the currently active/visible tab.

Suggested Fix

Scope the querySelector call to the currently active tab panel instead of the entire document. For example:

  document.addEventListener("keydown", (e) => {
      if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return;

      // Find the currently visible tab panel
      const activePanel = document.querySelector('.tab-panel:not([hidden]), .tab-panel.active');
      const scope = activePanel || document;

      if (e.key === "ArrowLeft") {
          e.preventDefault();
          const prevBtn = scope.querySelector('[\\@click="prevPage()"]');
          if (prevBtn && !prevBtn.disabled) prevBtn.click();
      } else if (e.key === "ArrowRight") {
          e.preventDefault();
          const nextBtn = scope.querySelector('[\\@click="nextPage()"]');
          if (nextBtn && !nextBtn.disabled) nextBtn.click();
      }
  });

The exact selector for the active panel (.tab-panel:not([hidden]), .tab-panel.active, [role="tabpanel"]:not([hidden]), etc.) should be adjusted to match the tab panel markup used in the Admin UI templates.

Related


๐Ÿ““ Logs / Error Output

Paste any relevant stack traces or logs here.
โš ๏ธ Do not paste secrets, credentials, or tokens.


๐Ÿง  Environment Info

You can retrieve most of this from the /version endpoint.

Key Value
Version or commit e.g. v0.9.0 or main@a1b2c3d
Runtime e.g. Python 3.11, Gunicorn
Platform / OS e.g. Ubuntu 22.04, macOS
Container e.g. Docker, Podman, none

๐Ÿงฉ Additional Context (optional)

Add any configuration details, flags, or related issues.

Metadata

Metadata

Assignees

Labels

COULDP3: Nice-to-have features with minimal impact if left out; included if time permitsbugSomething isn't workinguiUser Interface

Type

No fields configured for Bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    โšก