diff --git a/package.json b/package.json index 94976e0..33da554 100644 --- a/package.json +++ b/package.json @@ -120,16 +120,6 @@ { "command": "tailscale.openAdminConsole", "group": "overflow" - }, - { - "command": "tailscale.advancedServeView", - "group": "overflow", - "when": "tailscale.viewType == 'simple' && tailscale.env == 'development'" - }, - { - "command": "tailscale.simpleServeView", - "group": "overflow", - "when": "tailscale.viewType == 'advanced'" } ] }, @@ -164,11 +154,6 @@ "category": "tsdev", "title": "Reload Serve Panel" }, - { - "command": "tailscale.advancedServeView", - "title": "Advanced View", - "category": "tsdev" - }, { "command": "tailscale.simpleServeView", "title": "Simple View", diff --git a/src/extension.ts b/src/extension.ts index 5c48f39..bea9f50 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -94,20 +94,6 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - context.subscriptions.push( - vscode.commands.registerCommand('tailscale.advancedServeView', () => { - Logger.info('called tailscale.advancedServeView', 'command'); - servePanelProvider.showAdvancedView(); - }) - ); - - context.subscriptions.push( - vscode.commands.registerCommand('tailscale.simpleServeView', () => { - Logger.info('called tailscale.simpleServeView', 'command'); - servePanelProvider.showSimpleView(); - }) - ); - context.subscriptions.push( vscode.commands.registerCommand('tailscale.openFunnelPanel', () => { vscode.commands.executeCommand('tailscale-serve-view.focus'); diff --git a/src/serve-panel-provider.ts b/src/serve-panel-provider.ts index 9843286..4a65682 100644 --- a/src/serve-panel-provider.ts +++ b/src/serve-panel-provider.ts @@ -24,18 +24,6 @@ export class ServePanelProvider implements vscode.WebviewViewProvider { }); } - public async showAdvancedView() { - this.postMessage({ - type: 'showAdvancedView', - }); - } - - public async showSimpleView() { - this.postMessage({ - type: 'showSimpleView', - }); - } - resolveWebviewView(webviewView: vscode.WebviewView) { this._view = webviewView; webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); @@ -72,12 +60,6 @@ export class ServePanelProvider implements vscode.WebviewViewProvider { break; } - case 'setViewType': { - Logger.info('Called setViewType', 'serve-panel'); - vscode.commands.executeCommand('setContext', 'tailscale.viewType', m.params.type); - break; - } - case 'setFunnel': { Logger.info('Called setFunnel', 'serve-panel'); try { diff --git a/src/types.ts b/src/types.ts index 0c3b2ff..e792e70 100644 --- a/src/types.ts +++ b/src/types.ts @@ -97,13 +97,6 @@ interface SetFunnel { }; } -interface SetViewType { - type: 'setViewType'; - params: { - type: 'simple' | 'advanced'; - }; -} - interface WriteToClipboard { type: 'writeToClipboard'; params: { @@ -124,7 +117,6 @@ export type Message = | AddServe | ResetServe | SetFunnel - | SetViewType | WriteToClipboard | OpenLink; @@ -153,22 +145,7 @@ interface WebpackStillOk { type: 'webpackStillOk'; } -interface ShowAdvancedView { - type: 'showAdvancedView'; -} - -interface ShowSimpleView { - type: 'showSimpleView'; -} - -export type WebviewData = - | UpdateState - | RefreshState - | ShowAdvancedView - | ShowSimpleView - | WebpackOk - | WebpackInvalid - | WebpackStillOk; +export type WebviewData = UpdateState | RefreshState | WebpackOk | WebpackInvalid | WebpackStillOk; export type WebviewEvent = Event & { data: WebviewData }; export interface NewPortNotification { diff --git a/src/webviews/serve-panel/app.tsx b/src/webviews/serve-panel/app.tsx index fbdbc4b..0675bc9 100644 --- a/src/webviews/serve-panel/app.tsx +++ b/src/webviews/serve-panel/app.tsx @@ -1,325 +1,7 @@ -import React, { useState, useEffect } from 'react'; -import { VSCodeCheckbox, VSCodeLink, VSCodeButton } from '@vscode/webview-ui-toolkit/react'; +import React from 'react'; -import { vsCodeAPI } from '../../vscode-api'; import { SimpleView } from './simple-view'; -import { trimSuffix } from '../../utils/string'; -import { useServeStatusStore } from './store'; -import { ServeConfig, Handlers, ServeParams } from '../../types'; -import { PortInput } from './components/port-input'; -import { PathInput } from './components/path-input'; export const App = () => { - const { state, selectedAddress, showAdvanced } = useServeStatusStore(); - - return ( -
- {showAdvanced ? ( - - ) : ( - - )} -
- ); -}; - -function handleSubmit(e) { - e.preventDefault(); - const form = e.target; - const formData = new FormData(form); - - vsCodeAPI.postMessage({ - type: 'addServe', - params: { - protocol: 'https', - port: 443, - mountPoint: formData.get('mountPoint') as string, - source: `http://127.0.0.1:${formData.get('port')}${formData.get('path')}` as string, - }, - }); -} - -const ServeListMappings = ({ address, handlers, openSectionKey, setOpenSectionKey, funnel }) => { - const isOpen = openSectionKey === address; - const port = address.split(':')[1]; - // TODO(all): capture Funnel posts list from Capabilities property in status - const canEnablefunnel = [443, 8443, 10000].indexOf(parseInt(port, 10)) > -1; - - const handleSectionClick = (e) => { - e.stopPropagation(); - setOpenSectionKey(address); - - // persist the selection - useServeStatusStore.setState({ selectedAddress: address }); - }; - - function handleDelete(options: ServeParams) { - vsCodeAPI.postMessage({ - type: 'deleteServe', - params: options, - }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function toggleFunnel(e: any) { - vsCodeAPI.postMessage({ - type: 'setFunnel', - params: { port, allow: e.target.checked }, - }); - } - - const DNSName = address.split(':')[0]; - - return ( -
-
-
-
Serve ports - via HTTP ({port}) -
-
- {' '} - Public - - - - This enables Tailscale Funnel, which exposes the local port to the internet.{' '} - - Learn more. - - - -
-
- {isOpen && ( -
-
- {DNSName} -
-
- - - - - - - - - - - {Object.entries(handlers).flatMap(([mountPoint, { Proxy: source }]) => { - const sourceURL = new URL(source); - const addressURL = new URL(`http://${address}`); - const port = parseInt(addressURL.port); - - return ( - - - - - - - ); - })} - - - - - - - - -
ActiveTargetMount Point
- - - http://127.0.0.1:{sourceURL.port} - {sourceURL.pathname} - - https://{DNSName} - {mountPoint} -
- vsCodeAPI.writeToClipboard(`https://${address + mountPoint}`) - } - className="pl-2 codicon codicon-copy" - >
-
-
- handleDelete({ protocol: 'https', port, mountPoint, source }) - } - >
-
- - - http://127.0.0.1: - - - - https://{DNSName} - - - Save -
-
-
- )} -
- ); -}; - -const NewServeForm = ({ - portValue, - showPort, - serveStatus, -}: { - portValue: string; - showPort: boolean; - serveStatus: ServeConfig; -}) => { - const [port, setPort] = useState(portValue); - const [sourcePort, setSourcePort] = useState(''); - const [mountPoint, setMountPoint] = useState(''); - const [sourcePath, setSourcePath] = useState(''); - - const DNSName = trimSuffix(serveStatus.Self?.DNSName, '.'); - - function handleSubmit(e) { - e.preventDefault(); - vsCodeAPI.postMessage({ - type: 'addServe', - params: { - protocol: 'https', - port: parseInt(port), - mountPoint, - source: `http://127.0.0.1:${sourcePort}${sourcePath}` as string, - }, - }); - - // reset the form - setPort('443'); - setSourcePort(''); - setMountPoint(''); - setSourcePath(''); - } - - return ( -
- {showPort && ( -
-
-
Serve ports via HTTP ( - setPort(e.target.value)} minWidth={true} />) -
-
- {DNSName} -
-
- )} - - - - - - - - - - - - - - - - - - - -
ActiveTargetMount Point
- - - http://127.0.0.1: - setSourcePort(e.target.value)} - /> - setSourcePath(e.target.value)} /> - - {DNSName} - setMountPoint(e.target.value)} /> - - Save -
-
- ); -}; - -const ServeList = ({ - serveStatus, - selectedAddress, -}: { - serveStatus: ServeConfig; - selectedAddress: string | undefined; -}) => { - const [openSectionKey, setOpenSectionKey] = useState(selectedAddress); - - useEffect(() => { - if (openSectionKey) { - return; - } - - if (selectedAddress) { - setOpenSectionKey(selectedAddress); - } - - if (serveStatus.Web) { - setOpenSectionKey(Object.keys(serveStatus.Web)[0]); - } - }, [openSectionKey, selectedAddress, serveStatus]); - - return ( -
- {serveStatus.Web && - Object.entries(serveStatus.Web).map(([address, { Handlers }]) => { - const funnel = serveStatus.AllowFunnel ? serveStatus.AllowFunnel[address] : false; - return ( - - ); - })} - {!serveStatus.Web && ( - - )} -
- ); -}; - -const AdvancedView = ({ - serveStatus, - selectedAddress, -}: { - serveStatus: ServeConfig; - selectedAddress: string | undefined; -}) => { - const [showNewPort, setShowNewPort] = useState(false); - - return ( -
- - {showNewPort && } -
- setShowNewPort(!showNewPort)}> - {showNewPort ? 'Hide' : ''} New Serve Port - -
-
- ); + return ; }; diff --git a/src/webviews/serve-panel/index.tsx b/src/webviews/serve-panel/index.tsx index b810240..bbdef59 100644 --- a/src/webviews/serve-panel/index.tsx +++ b/src/webviews/serve-panel/index.tsx @@ -2,37 +2,14 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import { provideVSCodeDesignSystem, vsCodeButton } from '@vscode/webview-ui-toolkit'; import { App } from './app'; -import { useServeStatusStore } from './store'; -import { vsCodeAPI } from '../../vscode-api'; import type { WebviewEvent } from '../../types'; provideVSCodeDesignSystem().register(vsCodeButton()); import './index.css'; -useServeStatusStore.setState({}); - -// request initial data -// vsCodeAPI.postMessage({ type: 'refreshState' }); - window.addEventListener('message', (m: WebviewEvent) => { switch (m.data.type) { - case 'updateState': - useServeStatusStore.setState({ - state: m.data.state, - isLoaded: true, - }); - - break; - - case 'showAdvancedView': - useServeStatusStore.setState({ showAdvanced: true }); - break; - - case 'showSimpleView': - useServeStatusStore.setState({ showAdvanced: false }); - break; - // ignored dev messages case 'webpackOk': case 'webpackInvalid': diff --git a/src/webviews/serve-panel/store.ts b/src/webviews/serve-panel/store.ts deleted file mode 100644 index bdc2a6f..0000000 --- a/src/webviews/serve-panel/store.ts +++ /dev/null @@ -1,45 +0,0 @@ -import produce, { Draft } from 'immer'; -import create, { State, StateCreator } from 'zustand'; -import type { ServeConfig } from '../../types'; - -const immer = - ( - config: StateCreator) => void) => void> - ): StateCreator => - (set, get, api) => - config((fn) => set(produce(fn)), get, api); - -interface ValidationError { - path: string; - errors: string[]; - message: string; - type: string; -} - -type ServeStatusStoreState = { - state: ServeConfig; - selectedAddress: string | undefined; - errors: ValidationError[]; - isLoaded: boolean; - showAdvanced: boolean; - update: (fn: (draft: Draft) => void) => void; - setErrors: (errors: ValidationError[]) => void; -}; - -export const useServeStatusStore = create( - immer((set) => ({ - errors: [], - state: {}, - isLoaded: false, - selectedAddress: undefined, - showAdvanced: false, - update: (fn) => { - set(fn); - }, - setErrors: (errors) => { - set((draft) => { - draft.errors = errors; - }); - }, - })) -);