diff --git a/src/config-manager.ts b/src/config-manager.ts index bd9d8f3..2205b4a 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -12,6 +12,7 @@ interface Host { interface Config { defaultHost?: Host; hosts?: Record; + portDiscoSnoozeUntil?: number; } export class ConfigManager { diff --git a/src/extension.ts b/src/extension.ts index ac1daee..941a8ae 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,10 +24,10 @@ let tailscaleInstance: Tailscale; export async function activate(context: vscode.ExtensionContext) { vscode.commands.executeCommand('setContext', 'tailscale.env', process.env.NODE_ENV); - tailscaleInstance = await Tailscale.withInit(vscode); - const configManager = ConfigManager.withGlobalStorageUri(context.globalStorageUri); + tailscaleInstance = await Tailscale.withInit(vscode, configManager); + // walkthrough completion tailscaleInstance.serveStatus().then((status) => { // assume if we have any BackendState we are installed diff --git a/src/tailscale/cli.ts b/src/tailscale/cli.ts index 10d2501..199960d 100644 --- a/src/tailscale/cli.ts +++ b/src/tailscale/cli.ts @@ -8,6 +8,7 @@ import * as path from 'node:path'; import { LogLevel } from 'vscode'; import { trimSuffix } from '../utils'; import { EXTENSION_NS } from '../constants'; +import { ConfigManager } from '../config-manager'; const LOG_COMPONENT = 'tsrelay'; @@ -35,13 +36,15 @@ export class Tailscale { private notifyExit?: () => void; private socket?: string; private ws?: WebSocket; + private configManager: ConfigManager; - constructor(vscode: vscodeModule) { + constructor(vscode: vscodeModule, configManager: ConfigManager) { this._vscode = vscode; + this.configManager = configManager; } - static async withInit(vscode: vscodeModule): Promise { - const ts = new Tailscale(vscode); + static async withInit(vscode: vscodeModule, configManager: ConfigManager): Promise { + const ts = new Tailscale(vscode, configManager); await ts.init(); vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration('tailscale.portDiscovery.enabled')) { @@ -381,13 +384,38 @@ export class Tailscale { if (msg.type != 'newPort') { return; } + const snoozeUntil = this.configManager.config.portDiscoSnoozeUntil; + if (snoozeUntil && snoozeUntil >= Date.now()) { + return; + } const shouldServe = await this._vscode.window.showInformationMessage( msg.message, { modal: false }, - 'Serve' + 'Expose', + 'Not now', + 'Learn more' ); - if (shouldServe) { + if (shouldServe === 'Expose') { await this.runFunnel(msg.port); + } else if (shouldServe === 'Not now') { + // one hour + const snoozeDuration = 60 * 60 * 1000; + this.configManager.set('portDiscoSnoozeUntil', Date.now() + snoozeDuration); + const openSettings = await this._vscode.window.showInformationMessage( + 'Snoozed for 1 hour. You can fully turn off port discovery in the settings', + { modal: false }, + 'Open Settings' + ); + if (openSettings) { + this._vscode.commands.executeCommand( + 'workbench.action.openSettings', + 'tailscale.portDiscovery.enabled' + ); + } + } else if (shouldServe === 'Learn more') { + vscode.env.openExternal( + vscode.Uri.parse('https://tailscale.com/kb/1223/tailscale-funnel/') + ); } }); this._vscode.window.onDidOpenTerminal(async (e: vscode.Terminal) => { diff --git a/tsrelay/handler/portdisco.go b/tsrelay/handler/portdisco.go index cdf7952..6199f17 100644 --- a/tsrelay/handler/portdisco.go +++ b/tsrelay/handler/portdisco.go @@ -138,7 +138,7 @@ func (h *handler) handlePortUpdates(c *websocket.Conn, up []portlist.Port) error err = c.WriteJSON(&wsMessage{ Type: "newPort", Port: int(p.Port), - Message: fmt.Sprintf("Port %d was started by %q, would you like to share it over the internet with Tailscale Funnel?", p.Port, p.Process), + Message: fmt.Sprintf("%q started using port %d. Would you like to expose this port to the internet using Tailscale Funnel?", p.Process, p.Port), }) if err != nil { h.Unlock()