Files
ssh-manager/docs/superpowers/specs/2026-03-26-terminal-multi-tabs-design.md
2026-03-26 18:04:39 +08:00

4.3 KiB

2026-03-26 Terminal Multi Tabs Design

Background

The connection list already opens terminal sessions into the shared terminal workspace at /terminal, and the sidebar already renders terminal tabs. However, the current store deduplicates tabs by connectionId, so clicking 终端 for the same connection only focuses the existing tab instead of opening a new shell session.

Goal

  • Allow users to open multiple terminal tabs from the connection list for the same connection.
  • Keep each terminal tab as an independent shell session.
  • Preserve the current terminal workspace route and sidebar interaction model.

Non-Goals

  • No tab persistence across refresh.
  • No route change from /terminal to per-tab URLs.
  • No generic tab-system refactor shared with SFTP.
  • No terminal session restore or reconnect workflow.

Current State

  • frontend/src/stores/terminalTabs.ts manages terminal tabs.
  • openOrFocus(connection) reuses an existing tab when connectionId matches.
  • frontend/src/views/ConnectionsView.vue uses that method before routing to /terminal.
  • frontend/src/views/TerminalWorkspaceView.vue already mounts one TerminalWidget per tab keyed by tab.id, so multiple tabs can coexist as long as the store allows them.

Selected Approach

Keep the existing terminal workspace architecture and change only the terminal tab creation semantics: clicking 终端 always creates a new tab, even when the same connection already has open tabs.

1. Terminal tab creation becomes always-new

Update frontend/src/stores/terminalTabs.ts so the terminal action always creates a new tab entry:

  • remove the connectionId dedup behavior from the open action
  • generate a fresh tab.id every time
  • activate the newly created tab immediately

This preserves the current in-memory tab lifecycle while enabling multiple concurrent sessions to the same host.

2. Distinguishable tab titles for repeated connections

When the same connection is opened multiple times, sidebar labels must remain distinguishable.

Recommended title strategy:

  • first tab: Connection Name
  • second tab: Connection Name (2)
  • third tab: Connection Name (3)

The sequence is computed from currently open tabs for the same connectionId. No persistence is needed.

3. Connections entry behavior

Update frontend/src/views/ConnectionsView.vue so clicking 终端 calls the always-new tab action and routes to /terminal.

Result:

  • each click from the connection list opens a fresh shell session
  • users can intentionally keep several terminals open for the same host

4. Terminal workspace behavior stays unchanged

frontend/src/views/TerminalWorkspaceView.vue and frontend/src/components/TerminalWidget.vue do not need architectural changes:

  • the workspace already loops through tabs by tab.id
  • each active tab renders its own TerminalWidget
  • each widget maintains an independent xterm instance and WebSocket connection

This matches the desired UX: multiple tabs for the same connection are separate terminal sessions rather than alternate views of one shared session.

Behavior Kept Unchanged

  • Terminal route remains /terminal.
  • Sidebar terminal tab section remains the primary tab switcher.
  • Closing and activating adjacent terminal tabs continues to follow the current logic.
  • SFTP tab behavior remains unchanged.
  • Existing slate/cyan visual language remains unchanged.

Acceptance Criteria

  • Clicking 终端 for the same connection multiple times creates multiple terminal tabs.
  • Each new terminal tab becomes the active tab.
  • Repeated tabs for the same connection are visually distinguishable in the sidebar.
  • Switching between tabs preserves each tab's own terminal session output.
  • Closing a terminal tab keeps current close/activate behavior intact.
  • Opening tabs for different connections continues to work.

Verification

  • Run npm run build in frontend/.
  • Manual verification:
    1. Click 终端 on the same connection three times and confirm three tabs appear.
    2. Confirm the sidebar shows distinguishable titles for repeated tabs.
    3. Type different commands in different tabs for the same connection and confirm each tab keeps its own output.
    4. Close active and inactive terminal tabs and confirm focus changes remain correct.
    5. Re-check that opening terminal tabs for different connections still works.