mirror of
https://github.com/VaalaCat/frp-panel.git
synced 2025-09-26 19:31:18 +08:00
feat: advance mode for proxy mutate form
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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'))
|
||||
|
@@ -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'))
|
||||
},
|
||||
})
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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",
|
||||
|
@@ -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": "新建",
|
||||
|
Reference in New Issue
Block a user