mirror of
https://github.com/VaalaCat/frp-panel.git
synced 2025-10-05 07:17:03 +08:00
chore: frontend form style
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { Check, ChevronsUpDown } from "lucide-react"
|
import { Check } from "lucide-react"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover"
|
} from "@/components/ui/popover"
|
||||||
|
import { CaretSortIcon } from "@radix-ui/react-icons"
|
||||||
|
|
||||||
export interface ComboboxProps {
|
export interface ComboboxProps {
|
||||||
value?: string
|
value?: string
|
||||||
@@ -67,17 +68,17 @@ export function Combobox({
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
role="combobox"
|
role="combobox"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className={cn("w-full justify-between font-normal", className,
|
className={cn("w-full justify-between font-normal px-3", className,
|
||||||
!value && "text-muted-foreground"
|
!value && "text-muted-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{value
|
{value
|
||||||
? (dataList.find((item) => item.value === value)?.label || value)
|
? (dataList.find((item) => item.value === value)?.label || value)
|
||||||
: (placeholder || defaultPlaceholder)}
|
: (placeholder || defaultPlaceholder)}
|
||||||
<ChevronsUpDown className="opacity-50 h-[12px] w-[12px]" />
|
<CaretSortIcon className="h-4 w-4 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-[200px] p-0" align="start">
|
<PopoverContent className="w-[--radix-popover-trigger-width] p-0" align="start">
|
||||||
<Command>
|
<Command>
|
||||||
<CommandInput
|
<CommandInput
|
||||||
value={keyword}
|
value={keyword}
|
||||||
|
@@ -19,6 +19,7 @@ import {
|
|||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import { IsIDValid } from '@/lib/consts'
|
||||||
|
|
||||||
export const CreateClientDialog = ({refetchTrigger}: {refetchTrigger?: (randStr: string) => void}) => {
|
export const CreateClientDialog = ({refetchTrigger}: {refetchTrigger?: (randStr: string) => void}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -60,9 +61,11 @@ export const CreateClientDialog = ({refetchTrigger}: {refetchTrigger?: (randStr:
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<Label>{t('client.create.id')}</Label>
|
<Label>{t('client.create.id')}</Label>
|
||||||
<Input className="mt-2" value={clientID} onChange={(e) => setClientID(e.target.value)} />
|
<Input value={clientID} onChange={(e) => setClientID(e.target.value)} />
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button onClick={handleNewClient}>{t('client.create.submit')}</Button>
|
<Button onClick={handleNewClient}
|
||||||
|
disabled={!IsIDValid(clientID)}
|
||||||
|
className='w-full'>{t('client.create.submit')}</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@@ -18,8 +18,9 @@ import {
|
|||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import { IsIDValid } from '@/lib/consts'
|
||||||
|
|
||||||
export const CreateServerDialog = ({refetchTrigger}: {refetchTrigger?: (randStr: string) => void}) => {
|
export const CreateServerDialog = ({ refetchTrigger }: { refetchTrigger?: (randStr: string) => void }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [serverID, setServerID] = useState<string | undefined>()
|
const [serverID, setServerID] = useState<string | undefined>()
|
||||||
const [serverIP, setServerIP] = useState<string | undefined>()
|
const [serverIP, setServerIP] = useState<string | undefined>()
|
||||||
@@ -60,11 +61,13 @@ export const CreateServerDialog = ({refetchTrigger}: {refetchTrigger?: (randStr:
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<Label>{t('server.create.id')}</Label>
|
<Label>{t('server.create.id')}</Label>
|
||||||
<Input className="mt-2" value={serverID} onChange={(e) => setServerID(e.target.value)} />
|
<Input value={serverID} onChange={(e) => setServerID(e.target.value)} />
|
||||||
<Label>{t('server.create.ip')}</Label>
|
<Label>{t('server.create.ip')}</Label>
|
||||||
<Input className="mt-2" value={serverIP} onChange={(e) => setServerIP(e.target.value)} />
|
<Input value={serverIP} onChange={(e) => setServerIP(e.target.value)} />
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button onClick={handleNewServer}>{t('server.create.submit')}</Button>
|
<Button onClick={handleNewServer}
|
||||||
|
disabled={!IsIDValid(serverID) || !serverIP}
|
||||||
|
className='w-full'>{t('server.create.submit')}</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@@ -9,7 +9,6 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
@@ -47,6 +46,12 @@ export const ProxyConfigMutateDialog = ({ ...props }: ProxyConfigMutateDialogPro
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className='max-h-screen overflow-auto'>
|
<DialogContent className='max-h-screen overflow-auto'>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{t('proxy.config.create_proxy')}</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{t('proxy.config.create_proxy_description')}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
<ProxyConfigMutateForm {...props} />
|
<ProxyConfigMutateForm {...props} />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -113,14 +118,14 @@ export const ProxyConfigMutateForm = ({ overwrite, defaultProxyConfig, defaultOr
|
|||||||
value={proxyType}
|
value={proxyType}
|
||||||
setValue={(value) => { setProxyType(value as ProxyType) }}
|
setValue={(value) => { setProxyType(value as ProxyType) }}
|
||||||
/>
|
/>
|
||||||
<div className='flex flex-row w-full overflow-auto'>
|
|
||||||
{proxyConfigs && selectedServer && proxyConfigs.length > 0 &&
|
{proxyConfigs && selectedServer && proxyConfigs.length > 0 &&
|
||||||
proxyConfigs[0] && TypedProxyConfigValid(proxyConfigs[0]) &&
|
proxyConfigs[0] && TypedProxyConfigValid(proxyConfigs[0]) &&
|
||||||
|
<div className='flex flex-row w-full overflow-auto'>
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<VisitPreview server={selectedServer} typedProxyConfig={proxyConfigs[0]} />
|
<VisitPreview server={selectedServer} typedProxyConfig={proxyConfigs[0]} />
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<Label>{t('proxy.config.proxy_name')} </Label>
|
<Label>{t('proxy.config.proxy_name')} </Label>
|
||||||
<Input className='text-sm' defaultValue={proxyName} onChange={(e) => setProxyName(e.target.value)} disabled={disableChangeProxyName} />
|
<Input className='text-sm' defaultValue={proxyName} onChange={(e) => setProxyName(e.target.value)} disabled={disableChangeProxyName} />
|
||||||
{proxyName && newClientID && newServerID && <TypedProxyForm
|
{proxyName && newClientID && newServerID && <TypedProxyForm
|
||||||
|
@@ -353,6 +353,9 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
|
"create_proxy": "Create Tunnel",
|
||||||
|
"create_proxy_description": "Expose the client's services to the server. The same client tunnel name must be unique",
|
||||||
|
"close": "Close",
|
||||||
"create_success": "Create successful",
|
"create_success": "Create successful",
|
||||||
"create_failed": "Create failed",
|
"create_failed": "Create failed",
|
||||||
"select_server": "Select Server",
|
"select_server": "Select Server",
|
||||||
|
@@ -353,6 +353,9 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"create": "创建",
|
"create": "创建",
|
||||||
|
"create_proxy": "创建隧道",
|
||||||
|
"create_proxy_description": "将客户端的服务暴露在服务端,同一个客户端隧道名称必须唯一",
|
||||||
|
"close": "关闭",
|
||||||
"create_success": "创建成功",
|
"create_success": "创建成功",
|
||||||
"create_failed": "创建失败",
|
"create_failed": "创建失败",
|
||||||
"select_server": "选择服务器",
|
"select_server": "选择服务器",
|
||||||
|
@@ -24,6 +24,14 @@ export const TypedProxyConfigValid = (typedProxyCfg: TypedProxyConfig | undefine
|
|||||||
return (typedProxyCfg?.localPort && typedProxyCfg.localIP && typedProxyCfg.name && typedProxyCfg.type) ? true : false
|
return (typedProxyCfg?.localPort && typedProxyCfg.localIP && typedProxyCfg.name && typedProxyCfg.type) ? true : false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const IsIDValid = (clientID: string|undefined): boolean => {
|
||||||
|
if (clientID == undefined) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const regex = /^[a-zA-Z0-9-_]+$/;
|
||||||
|
return clientID.length > 0 && regex.test(clientID);
|
||||||
|
}
|
||||||
|
|
||||||
export const ClientConfigured = (client: Client | undefined): boolean => {
|
export const ClientConfigured = (client: Client | undefined): boolean => {
|
||||||
if (client == undefined) {
|
if (client == undefined) {
|
||||||
return false
|
return false
|
||||||
|
@@ -104,3 +104,10 @@
|
|||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.popover-content-width-full {
|
||||||
|
width: var(--radix-popover-trigger-width);
|
||||||
|
max-height: var(--radix-popover-content-available-height);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user