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() c := context.Background()
tmpCfg := appInstance.GetConfig() tmpCfg := appInstance.GetConfig()
if commonArgs.RpcHost != nil { if commonArgs.RpcHost != nil && len(*commonArgs.RpcHost) > 0 {
tmpCfg.Master.RPCHost = *commonArgs.RpcHost tmpCfg.Master.RPCHost = *commonArgs.RpcHost
tmpCfg.Master.APIHost = *commonArgs.RpcHost tmpCfg.Master.APIHost = *commonArgs.RpcHost
} }
if commonArgs.ApiHost != nil { if commonArgs.ApiHost != nil && len(*commonArgs.RpcHost) > 0 {
tmpCfg.Master.APIHost = *commonArgs.ApiHost tmpCfg.Master.APIHost = *commonArgs.ApiHost
} }
if commonArgs.RpcPort != nil { if commonArgs.RpcPort != nil && *commonArgs.RpcPort > 0 {
tmpCfg.Master.RPCPort = *commonArgs.RpcPort tmpCfg.Master.RPCPort = *commonArgs.RpcPort
} }
if commonArgs.ApiPort != nil { if commonArgs.ApiPort != nil && *commonArgs.ApiPort > 0 {
tmpCfg.Master.APIPort = *commonArgs.ApiPort tmpCfg.Master.APIPort = *commonArgs.ApiPort
} }
if commonArgs.ApiScheme != nil { if commonArgs.ApiScheme != nil && len(*commonArgs.ApiScheme) > 0 {
tmpCfg.Master.APIScheme = *commonArgs.ApiScheme tmpCfg.Master.APIScheme = *commonArgs.ApiScheme
} }
if commonArgs.ClientID != nil { if commonArgs.ClientID != nil && len(*commonArgs.ClientID) > 0 {
tmpCfg.Client.ID = *commonArgs.ClientID tmpCfg.Client.ID = *commonArgs.ClientID
} }
if commonArgs.ClientSecret != nil { if commonArgs.ClientSecret != nil && len(*commonArgs.ClientSecret) > 0 {
tmpCfg.Client.Secret = *commonArgs.ClientSecret tmpCfg.Client.Secret = *commonArgs.ClientSecret
} }
if commonArgs.ApiUrl != nil { if commonArgs.ApiUrl != nil && len(*commonArgs.ApiUrl) > 0 {
tmpCfg.Client.APIUrl = *commonArgs.ApiUrl tmpCfg.Client.APIUrl = *commonArgs.ApiUrl
} }
if commonArgs.RpcUrl != nil { if commonArgs.RpcUrl != nil && len(*commonArgs.RpcUrl) > 0 {
tmpCfg.Client.RPCUrl = *commonArgs.RpcUrl tmpCfg.Client.RPCUrl = *commonArgs.RpcUrl
} }

View File

@@ -27,6 +27,8 @@ import { ProxyConfig, Server } from '@/lib/pb/common'
import { TypedProxyConfigValid } from '@/lib/consts' import { TypedProxyConfigValid } from '@/lib/consts'
import { toast } from 'sonner' import { toast } from 'sonner'
import { $proxyTableRefetchTrigger } from '@/store/refetch-trigger' import { $proxyTableRefetchTrigger } from '@/store/refetch-trigger'
import { Switch } from '../ui/switch'
import { Textarea } from '../ui/textarea'
export type ProxyConfigMutateDialogProps = { export type ProxyConfigMutateDialogProps = {
overwrite?: boolean overwrite?: boolean
@@ -72,6 +74,9 @@ export const ProxyConfigMutateForm = ({
const [proxyType, setProxyType] = useState<ProxyType>('http') const [proxyType, setProxyType] = useState<ProxyType>('http')
const [selectedServer, setSelectedServer] = useState<Server | undefined>() const [selectedServer, setSelectedServer] = useState<Server | undefined>()
const supportedProxyTypes: ProxyType[] = ['http', 'tcp', 'udp'] const supportedProxyTypes: ProxyType[] = ['http', 'tcp', 'udp']
// advanced mode toggle
const [advancedMode, setAdvancedMode] = useState<boolean>(false)
const [rawConfig, setRawConfig] = useState<string>('{}')
const createProxyConfigMutation = useMutation({ const createProxyConfigMutation = useMutation({
mutationKey: ['createProxyConfig', newClientID, newServerID], mutationKey: ['createProxyConfig', newClientID, newServerID],
@@ -103,6 +108,12 @@ export const ProxyConfigMutateForm = ({
} }
}, [proxyName, proxyType]) }, [proxyName, proxyType])
useEffect(() => {
if (proxyConfigs) {
setRawConfig(JSON.stringify(proxyConfigs, null, 2))
}
}, [proxyConfigs, setRawConfig])
useEffect(() => { useEffect(() => {
if (defaultProxyConfig && defaultOriginalProxyConfig) { if (defaultProxyConfig && defaultOriginalProxyConfig) {
setProxyConfigs([defaultProxyConfig]) setProxyConfigs([defaultProxyConfig])
@@ -110,6 +121,7 @@ export const ProxyConfigMutateForm = ({
setProxyName(defaultProxyConfig.name) setProxyName(defaultProxyConfig.name)
setNewClientID(defaultOriginalProxyConfig.originClientId) setNewClientID(defaultOriginalProxyConfig.originClientId)
setNewServerID(defaultOriginalProxyConfig.serverId) setNewServerID(defaultOriginalProxyConfig.serverId)
setRawConfig(JSON.stringify([defaultProxyConfig], null, 2))
} }
}, [defaultProxyConfig, defaultOriginalProxyConfig]) }, [defaultProxyConfig, defaultOriginalProxyConfig])
@@ -119,6 +131,12 @@ export const ProxyConfigMutateForm = ({
<ServerSelector setServerID={setNewServerID} serverID={newServerID} setServer={setSelectedServer} /> <ServerSelector setServerID={setNewServerID} serverID={newServerID} setServer={setSelectedServer} />
<Label>{t('proxy.config.select_client')} </Label> <Label>{t('proxy.config.select_client')} </Label>
<ClientSelector setClientID={setNewClientID} clientID={newClientID} /> <ClientSelector setClientID={setNewClientID} clientID={newClientID} />
<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> <Label>{t('proxy.config.select_proxy_type')} </Label>
<BaseSelector <BaseSelector
dataList={supportedProxyTypes.map((type) => ({ value: type, label: type }))} dataList={supportedProxyTypes.map((type) => ({ value: type, label: type }))}
@@ -156,8 +174,33 @@ export const ProxyConfigMutateForm = ({
enablePreview={false} 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 <Button
disabled={!TypedProxyConfigValid(proxyConfigs[0])} 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={advancedMode ? proxyConfigs.length === 0 : !TypedProxyConfigValid(proxyConfigs[0])}
onClick={() => { onClick={() => {
if (!TypedProxyConfigValid(proxyConfigs[0])) { if (!TypedProxyConfigValid(proxyConfigs[0])) {
toast(t('proxy.config.invalid_config')) toast(t('proxy.config.invalid_config'))

View File

@@ -59,7 +59,7 @@ export const CreateWorkerDialog: React.FC<CreateWorkerDialogProps> = ({ refetchT
refetchTrigger(new Date().toISOString()) refetchTrigger(new Date().toISOString())
}, },
onError: (err: any) => { 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"> <div className="flex items-center space-x-1">
<span className="w-2 h-2 rounded-full bg-red-500" /> <span className="w-2 h-2 rounded-full bg-red-500" />
<span> <span>
{t('worker.status')}: {Clients}/{totalClients} {t('worker.status_text')}: {Clients}/{totalClients}
</span> </span>
</div> </div>
<div className="flex items-center space-x-1"> <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"> <div className="flex items-center space-x-1">
<span className="w-2 h-2 rounded-full bg-red-500" /> <span className="w-2 h-2 rounded-full bg-red-500" />
<span> <span>
{t('worker.status')}: {Ingresses}/{totalIngresses} {t('worker.status_text')}: {Ingresses}/{totalIngresses}
</span> </span>
</div> </div>
</div> </div>

View File

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

View File

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