import './tunnelsModal.component.scss'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ConfigService, NotificationsService, PartialProfile, Profile, ProfilesService } from 'tabby-core'; import { ForwardedPortConfig, PortForwardType } from 'tabby-ssh'; import { SidebarPlusI18nService } from '../i18n'; /** * The tunnel form's working copy. Ports are nullable here where * `ForwardedPortConfig` types them as `number`: a numeric input bound to 0 * renders a literal "0" the user has to clear before typing, so the draft * starts empty and only becomes a ForwardedPortConfig once validated. */ interface TunnelDraft { type: PortForwardType; host: string; port: number | null; targetAddress: string; targetPort: number | null; description: string; } /** * The plugin's own tunnel editor, and — by the user's explicit choice — the * only one. An entry handing over to Tabby's native `showPortForwarding()` * modal was built and validated alongside it, then dropped: "je veux * uniquement ma solution maison". * * A modal rather than the popup this started as, for the same reason as the * snippets and note editors: a form is a poor fit for a 300px box anchored to * the cursor. It used to carry its own positioning, screen-edge clamp and * click-outside exception — the last one because it is the only popup that * could lose a half-filled form to a stray click — all three of which a * centred modal makes moot (NgbModal already blocks clicks outside its own * backdrop from reaching the page, and never closes on Escape while a text * field would eat it first). * * What that settles, so it is not rediscovered as a bug: nothing here can * touch a session that is already running. Everything written goes to the * profile's configuration, which Tabby reads only when a session starts. * Acting on a live session would mean calling `SSHSession.addPortForward()`, * which calls `fw.startLocalListener()` and therefore needs a genuine * `ForwardedPort` — a class tabby-ssh does not export at runtime (checked * against the installed bundle, piège #13). Rebuilding one from an existing * forward's prototype would only work once the user already had a tunnel, * which is circular. */ export declare class TunnelsModalComponent { private profilesService; private config; private notifications; private modalInstance; private i18n; profile: PartialProfile; /** * Whether a given forward is one Tabby currently has mounted — decides if * its deletion is withheld. A callback rather than a one-time snapshot: * the tree recomputes this on the same 2s poll that drives its own * "Tunnels actifs" section, and a session can open or close while this * modal is sitting open. */ isLive: (forward: ForwardedPortConfig) => boolean; /** Whether `profile` has a live session right now — only used to decide whether the "takes effect at next launch" notice is worth showing. */ hasLiveSession: () => boolean; tunnelDraft: TunnelDraft; tunnelError: string | null; /** Index of the tunnel the form is editing, or null when it is adding a new one. */ editingTunnelIndex: number | null; constructor(profilesService: ProfilesService, config: ConfigService, notifications: NotificationsService, modalInstance: NgbActiveModal, i18n: SidebarPlusI18nService); /** Tunnels stored on the profile itself. */ get profileTunnels(): ForwardedPortConfig[]; get tunnelTypes(): PortForwardType[]; formatTunnelRow(forward: ForwardedPortConfig): string; /** * Loads an existing tunnel back into the form (double-click on its row). * Ports come back as null when zero so the field reads empty rather than * "0" — same reason the draft keeps them nullable in the first place; a * Dynamic forward is stored with an empty destination, and editing one * should not show a phantom port. */ startEditTunnel(index: number): void; cancelEditTunnel(): void; get isDynamicDraft(): boolean; /** * Which side of the connection each field refers to — it *inverts* * between Local and Remote, and the destination is always resolved from * the far end of the tunnel, so `localhost` means the server for a Local * forward. Left implicit, this is the kind of thing that gets a forward * pointed at the wrong machine on real infrastructure. */ get tunnelHint(): string; addProfileTunnel(): Promise; removeProfileTunnel(index: number): Promise; close(): void; } export {};