Path: blob/main/src/vs/sessions/contrib/tunnelHost/electron-browser/toggleRemoteConnectionsActionViewItem.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import './media/tunnelHost.css';6import * as dom from '../../../../base/browser/dom.js';7import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js';8import { BaseActionViewItem } from '../../../../base/browser/ui/actionbar/actionViewItems.js';9import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';10import { IAction } from '../../../../base/common/actions.js';11import { Codicon } from '../../../../base/common/codicons.js';12import { MarkdownString } from '../../../../base/common/htmlContent.js';13import { disposableTimeout } from '../../../../base/common/async.js';14import { localize } from '../../../../nls.js';15import { IHoverService } from '../../../../platform/hover/browser/hover.js';16import { ITunnelHostService } from '../common/tunnelHost.js';17import { SHOW_TUNNEL_HOST_OUTPUT_ID } from './tunnelHostService.js';18import { IManagedHover, IManagedHoverContent } from '../../../../base/browser/ui/hover/hover.js';1920/**21* Custom action view item for the toggle remote connections button.22* Provides pulse animation while connecting, hover with tunnel status,23* and a brief toast message after enabling.24*/25export class ToggleRemoteConnectionsActionViewItem extends BaseActionViewItem {2627private _iconElement: HTMLElement | undefined;28private _toastElement: HTMLElement | undefined;29private _hover: IManagedHover | undefined;30private _wasSharing = false;3132constructor(33action: IAction,34@ITunnelHostService private readonly _tunnelHostService: ITunnelHostService,35@IHoverService private readonly _hoverService: IHoverService,36) {37super(undefined, action);3839this._wasSharing = this._tunnelHostService.isSharing;4041this._register(this._tunnelHostService.onDidChangeStatus(() => {42this._updateState();43}));44}4546override render(container: HTMLElement): void {47super.render(container);4849if (!this.element) {50return;51}5253this.element.classList.add('tunnel-host-toggle');54this.element.tabIndex = 0;55this.element.role = 'button';5657// Icon58this._iconElement = dom.append(this.element, dom.$('span.tunnel-host-icon'));59this._iconElement.append(...renderLabelWithIcons(`$(${Codicon.radioTower.id})`));6061// Toast text (initially hidden)62this._toastElement = dom.append(this.element, dom.$('span.tunnel-host-toast'));6364// Hover65const hoverDelegate = getDefaultHoverDelegate('element');66this._hover = this._register(this._hoverService.setupManagedHover(67hoverDelegate, this.element, this._getHoverContent()68));6970this._updateState();71}7273private _updateState(): void {74if (!this.element) {75return;76}7778const isSharing = this._tunnelHostService.isSharing;79const isConnecting = this._tunnelHostService.isConnecting;8081// Toggle CSS classes for visual state82this.element.classList.toggle('sharing', isSharing);83this.element.classList.toggle('connecting', isConnecting);8485// Update hover content86this._hover?.update(this._getHoverContent());8788// Update ARIA89this.element.setAttribute('aria-label', this._getAriaLabel());90this.element.setAttribute('aria-pressed', String(isSharing));9192// Show toast when transitioning to sharing93if (isSharing && !this._wasSharing && !isConnecting) {94this._showToast();95} else if (!isSharing && this._wasSharing) {96this._hideToast();97}9899this._wasSharing = isSharing;100}101102private _showToast(): void {103if (!this._toastElement) {104return;105}106107this._toastElement.textContent = localize('tunnelHost.toast', "Remote session access is now enabled");108this._toastElement.classList.add('visible');109110disposableTimeout(() => {111this._hideToast();112}, 3000, this._store);113}114115private _hideToast(): void {116this._toastElement?.classList.remove('visible');117}118119private _getHoverContent(): IManagedHoverContent {120const lines: string[] = [];121122if (this._tunnelHostService.isConnecting) {123lines.push(localize('tunnelHost.hover.connecting', "Establishing tunnel connection..."));124} else if (this._tunnelHostService.isSharing) {125const info = this._tunnelHostService.sharingInfo;126if (info) {127lines.push(localize('tunnelHost.hover.sharing', "Remote session access enabled via tunnel '{0}'", info.tunnelName));128} else {129lines.push(localize('tunnelHost.hover.enabled', "Remote session access is enabled"));130}131} else {132lines.push(localize('tunnelHost.hover.idle', "Allow remote session access"));133}134135lines.push(`[${localize('tunnelHost.hover.showOutput', "Show Output")}](command:${SHOW_TUNNEL_HOST_OUTPUT_ID})`);136137const md = new MarkdownString(lines.join('\n\n'), { isTrusted: { enabledCommands: [SHOW_TUNNEL_HOST_OUTPUT_ID] } });138return { markdown: md, markdownNotSupportedFallback: lines[0] };139}140141private _getAriaLabel(): string {142if (this._tunnelHostService.isConnecting) {143return localize('tunnelHost.hover.connecting', "Establishing tunnel connection...");144}145if (this._tunnelHostService.isSharing) {146const info = this._tunnelHostService.sharingInfo;147if (info) {148return localize('tunnelHost.hover.sharing', "Remote session access enabled via tunnel '{0}'", info.tunnelName);149}150return localize('tunnelHost.hover.enabled', "Remote session access is enabled");151}152return localize('tunnelHost.hover.idle', "Allow remote session access");153}154155override dispose(): void {156super.dispose();157}158}159160161