mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-21 22:34:31 +01:00
Add status bar entry for forwarded ports
Fixes microsoft/vscode-remote-release#3825
This commit is contained in:
@@ -17,9 +17,9 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { FilterViewPaneContainer } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { ForwardedPortsView, VIEWLET_ID } from 'vs/workbench/contrib/remote/browser/remoteExplorer';
|
||||
import { AutomaticPortForwarding, ForwardedPortsView, VIEWLET_ID } from 'vs/workbench/contrib/remote/browser/remoteExplorer';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewDescriptor, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptor, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
@@ -37,14 +37,13 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ReconnectionWaitEvent, PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems';
|
||||
import { Action, IActionViewItem, IAction } from 'vs/base/common/actions';
|
||||
import { isStringArray } from 'vs/base/common/types';
|
||||
import { IRemoteExplorerService, MakeAddress, mapHasTunnelLocalhostOrAllInterfaces } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { forwardedPortsViewEnabled, OpenPortInBrowserAction } from 'vs/workbench/contrib/remote/browser/tunnelView';
|
||||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
@@ -56,9 +55,6 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { RemoteStatusIndicator } from 'vs/workbench/contrib/remote/browser/remoteIndicator';
|
||||
import { inQuickPickContextKeyValue } from 'vs/workbench/browser/quickaccess';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification';
|
||||
import { UrlFinder } from 'vs/workbench/contrib/remote/browser/urlFinder';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
|
||||
export interface HelpInformation {
|
||||
extensionDescription: IExtensionDescription;
|
||||
@@ -827,91 +823,6 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
class AutomaticPortForwarding extends Disposable implements IWorkbenchContribution {
|
||||
private contextServiceListener?: IDisposable;
|
||||
private urlFinder?: UrlFinder;
|
||||
private static AUTO_FORWARD_SETTING = 'remote.autoForwardPorts';
|
||||
|
||||
constructor(
|
||||
@ITerminalService private readonly terminalService: ITerminalService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IViewsService private readonly viewsService: IViewsService,
|
||||
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
this._register(configurationService.onDidChangeConfiguration((e) => {
|
||||
if (e.affectsConfiguration(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) {
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}));
|
||||
|
||||
if (this.environmentService.remoteAuthority) {
|
||||
this.contextServiceListener = this._register(this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(new Set(forwardedPortsViewEnabled.keys()))) {
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}));
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}
|
||||
|
||||
private tryStartStopUrlFinder() {
|
||||
if (this.configurationService.getValue(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) {
|
||||
this.startUrlFinder();
|
||||
} else {
|
||||
this.stopUrlFinder();
|
||||
}
|
||||
}
|
||||
|
||||
private startUrlFinder() {
|
||||
if (!this.urlFinder && !forwardedPortsViewEnabled.getValue(this.contextKeyService)) {
|
||||
return;
|
||||
}
|
||||
if (this.contextServiceListener) {
|
||||
this.contextServiceListener.dispose();
|
||||
}
|
||||
this.urlFinder = this._register(new UrlFinder(this.terminalService));
|
||||
this._register(this.urlFinder.onDidMatchLocalUrl(async (localUrl) => {
|
||||
if (mapHasTunnelLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, localUrl.host, localUrl.port)) {
|
||||
return;
|
||||
}
|
||||
const forwarded = await this.remoteExplorerService.forward(localUrl);
|
||||
if (forwarded) {
|
||||
const address = MakeAddress(forwarded.tunnelRemoteHost, forwarded.tunnelRemotePort);
|
||||
const message = nls.localize('remote.tunnelsView.automaticForward', "{0} from the remote has been forwarded to {1} locally.",
|
||||
address, forwarded.localAddress);
|
||||
const browserChoice: IPromptChoice = {
|
||||
label: OpenPortInBrowserAction.LABEL,
|
||||
run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address)
|
||||
};
|
||||
const showChoice: IPromptChoice = {
|
||||
label: nls.localize('remote.tunnelsView.showView', "Show Forwarded Ports"),
|
||||
run: () => {
|
||||
const remoteAuthority = this.environmentService.remoteAuthority;
|
||||
const explorerType: string[] | undefined = remoteAuthority ? [remoteAuthority.split('+')[0]] : undefined;
|
||||
if (explorerType) {
|
||||
this.remoteExplorerService.targetType = explorerType;
|
||||
}
|
||||
this.viewsService.openViewContainer(VIEWLET_ID);
|
||||
}
|
||||
};
|
||||
this.notificationService.prompt(Severity.Info, message, [browserChoice, showChoice], { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private stopUrlFinder() {
|
||||
if (this.urlFinder) {
|
||||
this.urlFinder.dispose();
|
||||
this.urlFinder = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteStatusIndicator, LifecyclePhase.Starting);
|
||||
|
||||
@@ -5,33 +5,42 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { Extensions, IViewDescriptorService, IViewsRegistry } from 'vs/workbench/common/views';
|
||||
import { Extensions, IViewDescriptorService, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
|
||||
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IRemoteExplorerService, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { forwardedPortsViewEnabled, ForwardPortAction, TunnelPanelDescriptor, TunnelViewModel } from 'vs/workbench/contrib/remote/browser/tunnelView';
|
||||
import { IRemoteExplorerService, MakeAddress, mapHasTunnelLocalhostOrAllInterfaces, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { forwardedPortsViewEnabled, ForwardPortAction, OpenPortInBrowserAction, TunnelPanelDescriptor, TunnelViewModel } from 'vs/workbench/contrib/remote/browser/tunnelView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { UrlFinder } from 'vs/workbench/contrib/remote/browser/urlFinder';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
|
||||
export const VIEWLET_ID = 'workbench.view.remote';
|
||||
|
||||
export class ForwardedPortsView extends Disposable implements IWorkbenchContribution {
|
||||
private contextKeyListener?: IDisposable;
|
||||
private _activityBadge?: IDisposable;
|
||||
private entryAccessor: IStatusbarEntryAccessor | undefined;
|
||||
|
||||
constructor(
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService,
|
||||
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
|
||||
@IActivityService private readonly activityService: IActivityService
|
||||
@IActivityService private readonly activityService: IActivityService,
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService
|
||||
) {
|
||||
super();
|
||||
this._register(Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).registerViewWelcomeContent(TUNNEL_VIEW_ID, {
|
||||
content: `Forwarded ports allow you to access your running applications locally.\n[Forward a Port](command:${ForwardPortAction.INLINE_ID})`,
|
||||
}));
|
||||
this.enableBadgeAndStatusBar();
|
||||
this.enableForwardedPortsView();
|
||||
this.enableBadge();
|
||||
}
|
||||
|
||||
private enableForwardedPortsView() {
|
||||
@@ -57,12 +66,19 @@ export class ForwardedPortsView extends Disposable implements IWorkbenchContribu
|
||||
}
|
||||
}
|
||||
|
||||
private enableBadge() {
|
||||
this._register(this.remoteExplorerService.tunnelModel.onForwardPort(() => this.updateActivityBadge()));
|
||||
this._register(this.remoteExplorerService.tunnelModel.onClosePort(() => this.updateActivityBadge()));
|
||||
private enableBadgeAndStatusBar() {
|
||||
this._register(this.remoteExplorerService.tunnelModel.onForwardPort(() => {
|
||||
this.updateActivityBadge();
|
||||
this.updateStatusBar();
|
||||
}));
|
||||
this._register(this.remoteExplorerService.tunnelModel.onClosePort(() => {
|
||||
this.updateActivityBadge();
|
||||
this.updateStatusBar();
|
||||
}));
|
||||
const disposable = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).onViewsRegistered(e => {
|
||||
if (e.find(view => view.views.find(viewDescriptor => viewDescriptor.id === TUNNEL_VIEW_ID))) {
|
||||
this.updateActivityBadge();
|
||||
this.updateStatusBar();
|
||||
disposable.dispose();
|
||||
}
|
||||
});
|
||||
@@ -81,4 +97,108 @@ export class ForwardedPortsView extends Disposable implements IWorkbenchContribu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateStatusBar() {
|
||||
if (!this.entryAccessor && this.remoteExplorerService.tunnelModel.forwarded.size > 0) {
|
||||
this._register(this.entryAccessor = this.statusbarService.addEntry(this.entry, 'status.forwardedPorts', nls.localize('status.forwardedPorts', "Forwarded Ports"), StatusbarAlignment.LEFT, 40));
|
||||
} else if (this.entryAccessor && this.remoteExplorerService.tunnelModel.forwarded.size === 0) {
|
||||
this.entryAccessor.dispose();
|
||||
this.entryAccessor = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private get entry(): IStatusbarEntry {
|
||||
return {
|
||||
text: '$(radio-tower) ' + nls.localize('remote.forwardedPorts.statusbarText', "Application running"),
|
||||
ariaLabel: nls.localize('remote.forwardedPorts.statusbarAria', "Application running and available locally through port forwarding"),
|
||||
tooltip: nls.localize('remote.forwardedPorts.statusbarTooltip', "Application available locally (port forwarded)"),
|
||||
command: `${TUNNEL_VIEW_ID}.focus`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class AutomaticPortForwarding extends Disposable implements IWorkbenchContribution {
|
||||
private contextServiceListener?: IDisposable;
|
||||
private urlFinder?: UrlFinder;
|
||||
private static AUTO_FORWARD_SETTING = 'remote.autoForwardPorts';
|
||||
|
||||
constructor(
|
||||
@ITerminalService private readonly terminalService: ITerminalService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IViewsService private readonly viewsService: IViewsService,
|
||||
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
this._register(configurationService.onDidChangeConfiguration((e) => {
|
||||
if (e.affectsConfiguration(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) {
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}));
|
||||
|
||||
if (this.environmentService.remoteAuthority) {
|
||||
this.contextServiceListener = this._register(this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(new Set(forwardedPortsViewEnabled.keys()))) {
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}));
|
||||
this.tryStartStopUrlFinder();
|
||||
}
|
||||
}
|
||||
|
||||
private tryStartStopUrlFinder() {
|
||||
if (this.configurationService.getValue(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) {
|
||||
this.startUrlFinder();
|
||||
} else {
|
||||
this.stopUrlFinder();
|
||||
}
|
||||
}
|
||||
|
||||
private startUrlFinder() {
|
||||
if (!this.urlFinder && !forwardedPortsViewEnabled.getValue(this.contextKeyService)) {
|
||||
return;
|
||||
}
|
||||
if (this.contextServiceListener) {
|
||||
this.contextServiceListener.dispose();
|
||||
}
|
||||
this.urlFinder = this._register(new UrlFinder(this.terminalService));
|
||||
this._register(this.urlFinder.onDidMatchLocalUrl(async (localUrl) => {
|
||||
if (mapHasTunnelLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, localUrl.host, localUrl.port)) {
|
||||
return;
|
||||
}
|
||||
const forwarded = await this.remoteExplorerService.forward(localUrl);
|
||||
if (forwarded) {
|
||||
const address = MakeAddress(forwarded.tunnelRemoteHost, forwarded.tunnelRemotePort);
|
||||
const message = nls.localize('remote.tunnelsView.automaticForward', "{0} from the remote has been forwarded to {1} locally.",
|
||||
address, forwarded.localAddress);
|
||||
const browserChoice: IPromptChoice = {
|
||||
label: OpenPortInBrowserAction.LABEL,
|
||||
run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address)
|
||||
};
|
||||
const showChoice: IPromptChoice = {
|
||||
label: nls.localize('remote.tunnelsView.showView', "Show Forwarded Ports"),
|
||||
run: () => {
|
||||
const remoteAuthority = this.environmentService.remoteAuthority;
|
||||
const explorerType: string[] | undefined = remoteAuthority ? [remoteAuthority.split('+')[0]] : undefined;
|
||||
if (explorerType) {
|
||||
this.remoteExplorerService.targetType = explorerType;
|
||||
}
|
||||
this.viewsService.openViewContainer(VIEWLET_ID);
|
||||
}
|
||||
};
|
||||
this.notificationService.prompt(Severity.Info, message, [browserChoice, showChoice], { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private stopUrlFinder() {
|
||||
if (this.urlFinder) {
|
||||
this.urlFinder.dispose();
|
||||
this.urlFinder = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user