feat: advance mode for proxy mutate form

This commit is contained in:
VaalaCat
2025-05-17 09:03:45 +00:00
parent a0263a6593
commit 282d6ee4b1
6 changed files with 113 additions and 56 deletions

View File

@@ -352,35 +352,35 @@ func patchConfig(appInstance app.Application, commonArgs CommonArgs) conf.Config
c := context.Background()
tmpCfg := appInstance.GetConfig()
if commonArgs.RpcHost != nil {
if commonArgs.RpcHost != nil && len(*commonArgs.RpcHost) > 0 {
tmpCfg.Master.RPCHost = *commonArgs.RpcHost
tmpCfg.Master.APIHost = *commonArgs.RpcHost
}
if commonArgs.ApiHost != nil {
if commonArgs.ApiHost != nil && len(*commonArgs.RpcHost) > 0 {
tmpCfg.Master.APIHost = *commonArgs.ApiHost
}
if commonArgs.RpcPort != nil {
if commonArgs.RpcPort != nil && *commonArgs.RpcPort > 0 {
tmpCfg.Master.RPCPort = *commonArgs.RpcPort
}
if commonArgs.ApiPort != nil {
if commonArgs.ApiPort != nil && *commonArgs.ApiPort > 0 {
tmpCfg.Master.APIPort = *commonArgs.ApiPort
}
if commonArgs.ApiScheme != nil {
if commonArgs.ApiScheme != nil && len(*commonArgs.ApiScheme) > 0 {
tmpCfg.Master.APIScheme = *commonArgs.ApiScheme
}
if commonArgs.ClientID != nil {
if commonArgs.ClientID != nil && len(*commonArgs.ClientID) > 0 {
tmpCfg.Client.ID = *commonArgs.ClientID
}
if commonArgs.ClientSecret != nil {
if commonArgs.ClientSecret != nil && len(*commonArgs.ClientSecret) > 0 {
tmpCfg.Client.Secret = *commonArgs.ClientSecret
}
if commonArgs.ApiUrl != nil {
if commonArgs.ApiUrl != nil && len(*commonArgs.ApiUrl) > 0 {
tmpCfg.Client.APIUrl = *commonArgs.ApiUrl
}
if commonArgs.RpcUrl != nil {
if commonArgs.RpcUrl != nil && len(*commonArgs.RpcUrl) > 0 {
tmpCfg.Client.RPCUrl = *commonArgs.RpcUrl
}

View File

@@ -27,6 +27,8 @@ import { ProxyConfig, Server } from '@/lib/pb/common'
import { TypedProxyConfigValid } from '@/lib/consts'
import { toast } from 'sonner'
import { $proxyTableRefetchTrigger } from '@/store/refetch-trigger'
import { Switch } from '../ui/switch'
import { Textarea } from '../ui/textarea'
export type ProxyConfigMutateDialogProps = {
overwrite?: boolean
@@ -72,6 +74,9 @@ export const ProxyConfigMutateForm = ({
const [proxyType, setProxyType] = useState<ProxyType>('http')
const [selectedServer, setSelectedServer] = useState<Server | undefined>()
const supportedProxyTypes: ProxyType[] = ['http', 'tcp', 'udp']
// advanced mode toggle
const [advancedMode, setAdvancedMode] = useState<boolean>(false)
const [rawConfig, setRawConfig] = useState<string>('{}')
const createProxyConfigMutation = useMutation({
mutationKey: ['createProxyConfig', newClientID, newServerID],
@@ -99,10 +104,16 @@ export const ProxyConfigMutateForm = ({
useEffect(() => {
if (proxyName && proxyType) {
setProxyConfigs([{...defaultProxyConfig, name: proxyName, type: proxyType }])
setProxyConfigs([{ ...defaultProxyConfig, name: proxyName, type: proxyType }])
}
}, [proxyName, proxyType])
useEffect(() => {
if (proxyConfigs) {
setRawConfig(JSON.stringify(proxyConfigs, null, 2))
}
}, [proxyConfigs, setRawConfig])
useEffect(() => {
if (defaultProxyConfig && defaultOriginalProxyConfig) {
setProxyConfigs([defaultProxyConfig])
@@ -110,6 +121,7 @@ export const ProxyConfigMutateForm = ({
setProxyName(defaultProxyConfig.name)
setNewClientID(defaultOriginalProxyConfig.originClientId)
setNewServerID(defaultOriginalProxyConfig.serverId)
setRawConfig(JSON.stringify([defaultProxyConfig], null, 2))
}
}, [defaultProxyConfig, defaultOriginalProxyConfig])
@@ -119,45 +131,76 @@ export const ProxyConfigMutateForm = ({
<ServerSelector setServerID={setNewServerID} serverID={newServerID} setServer={setSelectedServer} />
<Label>{t('proxy.config.select_client')} </Label>
<ClientSelector setClientID={setNewClientID} clientID={newClientID} />
<Label>{t('proxy.config.select_proxy_type')} </Label>
<BaseSelector
dataList={supportedProxyTypes.map((type) => ({ value: type, label: type }))}
value={proxyType}
setValue={(value) => {
setProxyType(value as ProxyType)
}}
/>
{proxyConfigs &&
selectedServer &&
proxyConfigs.length > 0 &&
proxyConfigs[0] &&
TypedProxyConfigValid(proxyConfigs[0]) && (
<div className="flex flex-row w-full overflow-auto">
<div className="flex flex-col">
<VisitPreview server={selectedServer} typedProxyConfig={proxyConfigs[0]} />
</div>
</div>
)}
<Label>{t('proxy.config.proxy_name')} </Label>
<Input
className="text-sm"
defaultValue={proxyName}
onChange={(e) => setProxyName(e.target.value)}
disabled={disableChangeProxyName}
/>
{proxyName && newClientID && newServerID && (
<TypedProxyForm
serverID={newServerID}
clientID={newClientID}
proxyName={proxyName}
defaultProxyConfig={proxyConfigs && proxyConfigs.length > 0 ? proxyConfigs[0] : undefined}
clientProxyConfigs={proxyConfigs}
setClientProxyConfigs={setProxyConfigs}
enablePreview={false}
/>
<div className="flex items-center space-x-2 my-2">
<Label>{t('proxy.config.advanced_mode')}</Label>
<Switch onCheckedChange={setAdvancedMode} />
</div>
{!advancedMode && (
<>
<Label>{t('proxy.config.select_proxy_type')} </Label>
<BaseSelector
dataList={supportedProxyTypes.map((type) => ({ value: type, label: type }))}
value={proxyType}
setValue={(value) => {
setProxyType(value as ProxyType)
}}
/>
{proxyConfigs &&
selectedServer &&
proxyConfigs.length > 0 &&
proxyConfigs[0] &&
TypedProxyConfigValid(proxyConfigs[0]) && (
<div className="flex flex-row w-full overflow-auto">
<div className="flex flex-col">
<VisitPreview server={selectedServer} typedProxyConfig={proxyConfigs[0]} />
</div>
</div>
)}
<Label>{t('proxy.config.proxy_name')} </Label>
<Input
className="text-sm"
defaultValue={proxyName}
onChange={(e) => setProxyName(e.target.value)}
disabled={disableChangeProxyName}
/>
{proxyName && newClientID && newServerID && (
<TypedProxyForm
serverID={newServerID}
clientID={newClientID}
proxyName={proxyName}
defaultProxyConfig={proxyConfigs && proxyConfigs.length > 0 ? proxyConfigs[0] : undefined}
clientProxyConfigs={proxyConfigs}
setClientProxyConfigs={setProxyConfigs}
enablePreview={false}
/>
)}
</>
)}
{advancedMode && (
<>
<Label>{t('proxy.config.raw_json')}</Label>
<Textarea
className="w-full h-64 font-mono text-sm p-2 border"
value={rawConfig}
onChange={(e) => setRawConfig(e.target.value)}
/>
<Button
onClick={() => {
try {
const parsed = JSON.parse(rawConfig) as TypedProxyConfig[]
setProxyConfigs(parsed)
} catch {
toast(t('proxy.config.invalid_json'))
return
}
}}
>
{t('proxy.config.draft')}
</Button>
</>
)}
<Button
disabled={!TypedProxyConfigValid(proxyConfigs[0])}
disabled={advancedMode ? proxyConfigs.length === 0 : !TypedProxyConfigValid(proxyConfigs[0])}
onClick={() => {
if (!TypedProxyConfigValid(proxyConfigs[0])) {
toast(t('proxy.config.invalid_config'))

View File

@@ -59,7 +59,7 @@ export const CreateWorkerDialog: React.FC<CreateWorkerDialogProps> = ({ refetchT
refetchTrigger(new Date().toISOString())
},
onError: (err: any) => {
toast(err?.message || t('worker.create'))
toast(err?.message || t('worker.create.error'))
},
})

View File

@@ -230,7 +230,7 @@ export function WorkerStatus({ workerId, clients = [], compact = false }: Worker
<div className="flex items-center space-x-1">
<span className="w-2 h-2 rounded-full bg-red-500" />
<span>
{t('worker.status')}: {Clients}/{totalClients}
{t('worker.status_text')}: {Clients}/{totalClients}
</span>
</div>
<div className="flex items-center space-x-1">
@@ -242,7 +242,7 @@ export function WorkerStatus({ workerId, clients = [], compact = false }: Worker
<div className="flex items-center space-x-1">
<span className="w-2 h-2 rounded-full bg-red-500" />
<span>
{t('worker.status')}: {Ingresses}/{totalIngresses}
{t('worker.status_text')}: {Ingresses}/{totalIngresses}
</span>
</div>
</div>

View File

@@ -287,8 +287,12 @@
"create_failed": "Create failed",
"select_server": "Select Server",
"select_client": "Select Client",
"advanced_mode": "Advanced Mode",
"select_proxy_type": "Select Tunnel Type",
"proxy_name": "Tunnel Name",
"raw_json": "Original Config",
"invalid_json": "Json Invalid",
"draft": "Draft",
"invalid_config": "Invalid configuration",
"submit": "Submit"
},
@@ -542,6 +546,8 @@
"delete_description": "Ingress deleted successfully"
},
"create": {
"success": "Create Success",
"error": "Create Error",
"button": "Create Worker",
"title": "Create Worker",
"description": "Create a new Worker",
@@ -574,9 +580,10 @@
"healthy": "Healthy",
"degraded": "Degraded",
"clients": "Deployments",
"running": "Running",
"ingresses": "Ingresses"
}
"ingresses": "Ingresses",
"running": "Running"
},
"status_text": "Status"
},
"status": {
"new": "New",

View File

@@ -286,8 +286,12 @@
"create_failed": "创建失败",
"select_server": "选择服务器",
"select_client": "选择客户端",
"advanced_mode": "高级模式",
"select_proxy_type": "选择隧道类型",
"proxy_name": "隧道名称",
"raw_json": "原始配置文件",
"invalid_json": "JSON非法",
"draft": "暂存",
"invalid_config": "配置不正确",
"submit": "提交"
},
@@ -540,6 +544,8 @@
"delete_description": "入口已成功删除"
},
"create": {
"success": "创建成功",
"error": "创建失败",
"button": "创建",
"title": "创建Worker",
"description": "创建一个新的Worker",
@@ -572,9 +578,10 @@
"healthy": "健康",
"degraded": "降级",
"clients": "部署",
"running": "运行中",
"ingresses": "入口"
}
"ingresses": "入口",
"running": "运行中"
},
"status_text": "状态"
},
"status": {
"new": "新建",