mirror of
https://github.com/VaalaCat/frp-panel.git
synced 2025-09-26 19:31:18 +08:00
feat: add support change protocol from client to server
This commit is contained in:
@@ -82,7 +82,16 @@ func UpdateFrpcHander(c context.Context, req *pb.UpdateFRPCRequest) (*pb.UpdateF
|
||||
}
|
||||
|
||||
cliCfg.ServerAddr = srv.ServerIP
|
||||
cliCfg.ServerPort = srvConf.BindPort
|
||||
switch cliCfg.Transport.Protocol {
|
||||
case "tcp":
|
||||
cliCfg.ServerPort = srvConf.BindPort
|
||||
case "kcp":
|
||||
cliCfg.ServerPort = srvConf.KCPBindPort
|
||||
case "quic":
|
||||
cliCfg.ServerPort = srvConf.QUICBindPort
|
||||
default:
|
||||
cliCfg.ServerPort = srvConf.BindPort
|
||||
}
|
||||
cliCfg.User = userInfo.GetUserName()
|
||||
cliCfg.Auth = v1.AuthClientConfig{}
|
||||
cliCfg.Metadatas = map[string]string{
|
||||
|
164
www/components/base/form-field.tsx
Normal file
164
www/components/base/form-field.tsx
Normal file
@@ -0,0 +1,164 @@
|
||||
import React from 'react'
|
||||
import { Control } from 'react-hook-form'
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import StringListInput from './list-input'
|
||||
|
||||
export const HostField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '127.0.0.1'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export const PortField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: number
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '1234'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export const SecretStringField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || "secret"} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const StringField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '127.0.0.1'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const StringArrayField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string[]
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<StringListInput placeholder={placeholder || '/path'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
@@ -15,7 +15,6 @@ import { TypedProxyConfig } from '@/types/proxy'
|
||||
import { ClientSelector } from '../base/client-selector'
|
||||
import { ServerSelector } from '../base/server-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
export interface FRPCFormCardProps {
|
||||
clientID?: string
|
||||
|
@@ -3,7 +3,7 @@ import React, { useEffect } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Label } from '@radix-ui/react-label'
|
||||
import { HTTPProxyForm, STCPProxyForm, TCPProxyForm, TypedProxyForm, UDPProxyForm } from './proxy_form'
|
||||
import { TypedProxyForm } from './proxy_form'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Client, RespCode } from '@/lib/pb/common'
|
||||
import { ClientConfig } from '@/types/client'
|
||||
@@ -13,10 +13,11 @@ import { Input } from '@/components/ui/input'
|
||||
import { AccordionHeader } from '@radix-ui/react-accordion'
|
||||
import { QueryObserverResult, RefetchOptions, useMutation } from '@tanstack/react-query'
|
||||
import { updateFRPC } from '@/api/frp'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { GetClientResponse } from '@/lib/pb/api_client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
import { BaseSelector } from '../base/selector'
|
||||
import { ConnectionProtocols } from '@/lib/consts'
|
||||
|
||||
export interface FRPCFormProps {
|
||||
clientID: string
|
||||
@@ -28,10 +29,17 @@ export interface FRPCFormProps {
|
||||
setClientProxyConfigs: React.Dispatch<React.SetStateAction<TypedProxyConfig[]>>
|
||||
}
|
||||
|
||||
export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, client, refetchClient, clientProxyConfigs, setClientProxyConfigs }) => {
|
||||
export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, clientConfig, client, refetchClient, clientProxyConfigs, setClientProxyConfigs }) => {
|
||||
const { t } = useTranslation()
|
||||
const [proxyType, setProxyType] = useState<ProxyType>('http')
|
||||
const [proxyName, setProxyName] = useState<string | undefined>()
|
||||
const [protocol, setProtocol] = useState<string | undefined>("tcp")
|
||||
|
||||
useEffect(() => {
|
||||
if (clientConfig.transport?.protocol) {
|
||||
setProtocol(clientConfig.transport?.protocol)
|
||||
}
|
||||
}, [clientConfig])
|
||||
|
||||
const handleTypeChange = (value: string) => {
|
||||
setProxyType(value as ProxyType)
|
||||
@@ -68,6 +76,10 @@ export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, client,
|
||||
config: Buffer.from(
|
||||
JSON.stringify({
|
||||
proxies: clientProxyConfigs,
|
||||
transport: {
|
||||
...clientConfig.transport,
|
||||
protocol,
|
||||
}
|
||||
} as ClientConfig),
|
||||
),
|
||||
serverId: serverID,
|
||||
@@ -86,7 +98,7 @@ export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, client,
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex flex-col space-y-2'>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button className="my-2">{t('proxy.form.add')}</Button>
|
||||
@@ -115,6 +127,11 @@ export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, client,
|
||||
</Button>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Label className="text-sm font-medium">{t('proxy.form.protocol')}</Label>
|
||||
<BaseSelector value={protocol} setValue={setProtocol}
|
||||
dataList={ConnectionProtocols.map((item) => { return { label: item, value: item } })}
|
||||
placeholder={t('proxy.form.protocol')}
|
||||
label={t('proxy.form.protocol')} />
|
||||
<Accordion type="single" defaultValue="proxies" collapsible key={clientID + serverID + client}>
|
||||
<AccordionItem value="proxies">
|
||||
<AccordionTrigger>
|
||||
@@ -165,6 +182,6 @@ export const FRPCForm: React.FC<FRPCFormProps> = ({ clientID, serverID, client,
|
||||
>
|
||||
{t('proxy.form.submit')}
|
||||
</Button>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@@ -4,10 +4,9 @@ import React from 'react'
|
||||
import { ZodPortSchema, ZodStringOptionalSchema, ZodStringSchema } from '@/lib/consts'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { Control, useForm } from 'react-hook-form'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Form, FormDescription } from '@/components/ui/form'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { YesIcon } from '@/components/ui/icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -15,7 +14,13 @@ import { useQuery } from '@tanstack/react-query'
|
||||
import { getServer } from '@/api/server'
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
import { VisitPreview } from '../base/visit-preview'
|
||||
import StringListInput from '../base/list-input'
|
||||
import {
|
||||
HostField,
|
||||
PortField,
|
||||
SecretStringField,
|
||||
StringArrayField,
|
||||
StringField
|
||||
} from '../base/form-field'
|
||||
|
||||
export const TCPConfigSchema = z.object({
|
||||
remotePort: ZodPortSchema,
|
||||
@@ -55,163 +60,6 @@ export interface ProxyFormProps {
|
||||
setClientProxyConfigs: React.Dispatch<React.SetStateAction<TypedProxyConfig[]>>
|
||||
}
|
||||
|
||||
const HostField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '127.0.0.1'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const PortField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: number
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '1234'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const SecretStringField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || "secret"} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const StringField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<Input className='text-sm' placeholder={placeholder || '127.0.0.1'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const StringArrayField = ({
|
||||
control,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
}: {
|
||||
control: Control<any>
|
||||
name: string
|
||||
label: string
|
||||
placeholder?: string
|
||||
defaultValue?: string[]
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<FormField
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(label)}</FormLabel>
|
||||
<FormControl>
|
||||
<StringListInput placeholder={placeholder || '/path'} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const TypedProxyForm: React.FC<ProxyFormProps> = ({ serverID, clientID, defaultProxyConfig, proxyName, clientProxyConfigs, setClientProxyConfigs, enablePreview }) => {
|
||||
if (!defaultProxyConfig) {
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { ServerConfig } from '@/types/server'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import * as z from 'zod'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Form } from '@/components/ui/form'
|
||||
import { ZodIPSchema, ZodPortSchema, ZodStringSchema } from '@/lib/consts'
|
||||
import { RespCode, Server } from '@/lib/pb/common'
|
||||
import { updateFRPS } from '@/api/frp'
|
||||
@@ -13,6 +12,7 @@ import { useMutation } from '@tanstack/react-query'
|
||||
import { Label } from '@radix-ui/react-label'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
import { HostField, PortField } from '../base/form-field'
|
||||
|
||||
const ServerConfigSchema = z.object({
|
||||
bindAddr: ZodIPSchema.default('0.0.0.0').optional(),
|
||||
@@ -21,6 +21,8 @@ const ServerConfigSchema = z.object({
|
||||
vhostHTTPPort: ZodPortSchema.optional(),
|
||||
subDomainHost: ZodStringSchema.optional(),
|
||||
publicHost: ZodStringSchema.optional(),
|
||||
quicBindPort: ZodPortSchema.optional(),
|
||||
kcpBindPort: ZodPortSchema.optional(),
|
||||
})
|
||||
|
||||
export const ServerConfigZodSchema = ServerConfigSchema
|
||||
@@ -48,7 +50,7 @@ const FRPSForm: React.FC<FRPSFormProps> = ({ serverID, server }) => {
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof ServerConfigZodSchema>) => {
|
||||
try {
|
||||
const {publicHost, ...rest} = values
|
||||
const { publicHost, ...rest } = values
|
||||
let resp = await updateFrps.mutateAsync({
|
||||
serverIp: publicHost,
|
||||
serverId: serverID,
|
||||
@@ -59,7 +61,7 @@ const FRPSForm: React.FC<FRPSFormProps> = ({ serverID, server }) => {
|
||||
} as ServerConfig),
|
||||
),
|
||||
})
|
||||
toast(resp.status?.code === RespCode.SUCCESS ? t('server.operation.update_success') : t('server.operation.update_failed'),{
|
||||
toast(resp.status?.code === RespCode.SUCCESS ? t('server.operation.update_success') : t('server.operation.update_failed'), {
|
||||
description: resp.status?.message,
|
||||
})
|
||||
} catch (error) {
|
||||
@@ -80,87 +82,14 @@ const FRPSForm: React.FC<FRPSFormProps> = ({ serverID, server }) => {
|
||||
{serverID && (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 px-0.5">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="publicHost"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.public_host')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={server?.ip}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bindPort"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.bind_port')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue={7000}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bindAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.bind_addr')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
defaultValue="0.0.0.0"
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="proxyBindAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.proxy_bind_addr')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="vhostHTTPPort"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.vhost_http_port')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="subDomainHost"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server.form.subdomain_host')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="example.com" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<HostField name="publicHost" label={t('server.form.public_host')} placeholder='8.8.8.8' control={form.control} defaultValue={server?.ip}/>
|
||||
<PortField name="bindPort" label={t('server.form.bind_port')} control={form.control} />
|
||||
<HostField name="bindAddr" label={t('server.form.bind_addr')} control={form.control} />
|
||||
<HostField name="proxyBindAddr" label={t('server.form.proxy_bind_addr')} control={form.control} />
|
||||
<PortField name="vhostHTTPPort" label={t('server.form.vhost_http_port')} control={form.control} />
|
||||
<HostField name="subDomainHost" label={t('server.form.subdomain_host')} control={form.control} />
|
||||
<PortField name="quicBindPort" label={t('server.form.quic_bind_port')} control={form.control} />
|
||||
<PortField name="kcpBindPort" label={t('server.form.kcp_bind_port')} control={form.control} />
|
||||
<Button type="submit">{t('common.submit')}</Button>
|
||||
</form>
|
||||
</Form>
|
||||
|
@@ -200,7 +200,9 @@
|
||||
"bind_addr": "FRPs Listen Address",
|
||||
"proxy_bind_addr": "Proxy Listen Address",
|
||||
"vhost_http_port": "HTTP Listen Port",
|
||||
"subdomain_host": "Subdomain Host"
|
||||
"subdomain_host": "Subdomain Host",
|
||||
"quic_bind_port": "Quic Bind Port",
|
||||
"kcp_bind_port":"KCP Bind Port"
|
||||
},
|
||||
"editor": {
|
||||
"comment": "Node {{id}} Comment",
|
||||
|
@@ -207,7 +207,9 @@
|
||||
"bind_addr": "FRPs 监听地址",
|
||||
"proxy_bind_addr": "代理监听地址",
|
||||
"vhost_http_port": "HTTP 监听端口",
|
||||
"subdomain_host": "域名后缀"
|
||||
"subdomain_host": "域名后缀",
|
||||
"quic_bind_port": "Quic 监听端口",
|
||||
"kcp_bind_port":"KCP 监听端口"
|
||||
},
|
||||
"create": {
|
||||
"button": "新建",
|
||||
|
@@ -22,11 +22,13 @@ export const ZodEmailSchema = z.string({ required_error: 'validation.required' }
|
||||
.min(1, { message: 'validation.required' })
|
||||
.email({ message: 'auth.email.invalid' })
|
||||
|
||||
export const ConnectionProtocols = ["tcp", "kcp", "quic", "websocket", "wss"]
|
||||
|
||||
export const TypedProxyConfigValid = (typedProxyCfg: TypedProxyConfig | undefined): boolean => {
|
||||
return (typedProxyCfg?.localPort && typedProxyCfg.localIP && typedProxyCfg.name && typedProxyCfg.type) ? true : false
|
||||
}
|
||||
|
||||
export const IsIDValid = (clientID: string|undefined): boolean => {
|
||||
export const IsIDValid = (clientID: string | undefined): boolean => {
|
||||
if (clientID == undefined) {
|
||||
return false
|
||||
}
|
||||
|
@@ -3,10 +3,10 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build && rm -rf ../cmd/frpp/out && cp -r out ../cmd/frpp",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"dev": "bunx next dev",
|
||||
"build": "bunx next build && rm -rf ../cmd/frpp/out && cp -r out ../cmd/frpp",
|
||||
"start": "bunx next start",
|
||||
"lint": "bunx next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.3.4",
|
||||
|
Reference in New Issue
Block a user