diff --git a/webview/src/ConfigEditor/proxyFields.tsx b/webview/src/ConfigEditor/proxyFields.tsx index 60f36b6..abfba19 100644 --- a/webview/src/ConfigEditor/proxyFields.tsx +++ b/webview/src/ConfigEditor/proxyFields.tsx @@ -1,17 +1,16 @@ import * as React from 'react'; +import { FieldConfig } from '../FieldTypes/config'; import { FieldDropdown } from '../FieldTypes/dropdown'; import { FieldNumber } from '../FieldTypes/number'; import { FieldString } from '../FieldTypes/string'; -import { connect } from '../redux'; import { FileSystemConfig } from '../types/fileSystemConfig'; import type { FieldFactory, FSCChanged, FSCChangedMultiple } from './fields'; -function proxy(config: FileSystemConfig, onChange: FSCChanged<'proxy'>): React.ReactElement { +function hostAndPort(config: FileSystemConfig, onChange: FSCChanged<'proxy'>): React.ReactElement { const onChangeHost = (host: string) => onChange('proxy', { ...config.proxy!, host }); const onChangePort = (port: number) => onChange('proxy', { ...config.proxy!, port }); console.log('Current config:', config); return -

{new Date().toString()}

): React.R
; } -interface HopFieldProps { - config: FileSystemConfig; - configs: [name: string, label: string][]; - onChange: FSCChanged<'hop'>; -} -const HopField = connect(({ config, configs, onChange }: HopFieldProps) => { - const callback = (newValue?: [string, string]) => onChange('hop', newValue?.[0]); +function hop(config: FileSystemConfig, onChange: FSCChanged<'hop'>): React.ReactElement { + const callback = (newValue?: FileSystemConfig) => onChange('hop', newValue?.name); const description = 'Use another configuration as proxy, using a SSH tunnel through the targeted config to the actual remote system'; - const displayName = (item: [string, string]) => item[1]; - const value = config.hop ? [config.hop, configs.find(c => c[0] === config.hop)?.[1] || config.hop] as const : undefined; - return ; -})>(state => { - const pairs = new Map(); - for (const { name, label } of state.data.configs) { - pairs.set(name, label || name); - } - return { configs: Array.from(pairs) }; -}); + return ; +} -const ProxyTypeToString = { - http: 'HTTP', - socks4: 'SOCKS 4', - socks5: 'SOCKS 5', -} as const; -const ProxyStringToType = { - 'HTTP': 'http', - 'SOCKS 4': 'socks4', - 'SOCKS 5': 'socks5', - 'SSH Hop': 'hop', -} as const; -type ProxyStrings = keyof typeof ProxyStringToType; +enum ProxyType { http, socks4, socks5, hop } +const ProxyTypeNames: Record = { + [ProxyType.http]: 'HTTP', + [ProxyType.socks4]: 'SOCKS 4', + [ProxyType.socks5]: 'SOCKS 5', + [ProxyType.hop]: 'SSH Hop', +}; -function merged(config: FileSystemConfig, onChange: FSCChanged, onChangeMultiple: FSCChangedMultiple): React.ReactElement | null { - function callback(newValue?: ProxyStrings) { - // Fields starting with _ don't get saved to file - // We use it here so we know when to display the hop stuff +function Merged(props: { config: FileSystemConfig, onChange: FSCChanged, onChangeMultiple: FSCChangedMultiple }): React.ReactElement | null { + const { config, onChange, onChangeMultiple } = props; + const [showHop, setShowHop] = React.useState(!!config.hop); + function callback(newValue?: ProxyType) { if (!newValue) { + setShowHop(false); return onChangeMultiple({ - ['_hop' as any]: undefined, hop: undefined, proxy: undefined, }); } - const newType = ProxyStringToType[newValue]; - if (newType === 'hop') { - return onChangeMultiple({ - ['_hop' as any]: true, - proxy: undefined, - }); + if (newValue === ProxyType.hop) { + setShowHop(true); + return onChangeMultiple({ proxy: undefined }); } + setShowHop(false); return onChangeMultiple({ - ['_hop' as any]: undefined, hop: undefined, proxy: { host: '', port: 22, ...config.proxy, - type: newType, + type: ProxyType[newValue] as any, } }); } const description = 'The type of proxy to use when connecting to the remote system'; - const values: ProxyStrings[] = ['SSH Hop', 'SOCKS 4', 'SOCKS 5', 'HTTP']; - const showHop = config.hop || (config as any)._hop; - const type = config.proxy && config.proxy.type; - const value = showHop ? 'SSH Hop' : (type && ProxyTypeToString[type]); + const values: ProxyType[] = [ProxyType.hop, ProxyType.socks4, ProxyType.socks5, ProxyType.http]; + const type = config.proxy?.type; + const value = (config.hop || showHop) ? ProxyType.hop : (type && ProxyType[type]); return - - {showHop && } - {config.proxy && proxy(config, onChange)} + ProxyTypeNames[i!]} onChange={callback} optional /> + {(config.hop || showHop) && hop(config, onChange)} + {config.proxy && hostAndPort(config, onChange)} ; } -export const PROXY_FIELD: FieldFactory = merged; \ No newline at end of file +export const PROXY_FIELD: FieldFactory = (config, onChange, onChangeMultiple) => + ; diff --git a/webview/src/FieldTypes/base.tsx b/webview/src/FieldTypes/base.tsx index 129ea1a..d4ffe21 100644 --- a/webview/src/FieldTypes/base.tsx +++ b/webview/src/FieldTypes/base.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { FieldGroup } from './group'; import './index.css'; -interface Props { +export interface Props { label: string; description?: string; value: T; diff --git a/webview/src/FieldTypes/config.tsx b/webview/src/FieldTypes/config.tsx new file mode 100644 index 0000000..e413e1c --- /dev/null +++ b/webview/src/FieldTypes/config.tsx @@ -0,0 +1,30 @@ +import { connect } from '../redux'; +import { FileSystemConfig, formatConfigLocation } from '../types/fileSystemConfig'; +import type { Props as FieldBaseProps } from './base'; +import { FieldDropdown, Props as FieldDropdownProps } from './dropdown'; + +type Props = Omit, 'value'> & FieldDropdownProps & { + /** + * Defaults to `'full'`. Determines how `values` and the default `displayName`. + * In which way to display configs in the dropdown and how to handle duplicate: + * - `full`: Display `