mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-13 10:26:38 +08:00
prettier
This commit is contained in:
@@ -1,18 +1,32 @@
|
||||
'use client';
|
||||
|
||||
import {useEffect} from 'react';
|
||||
import {zodResolver} from '@hookform/resolvers/zod';
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import {useForm} from 'react-hook-form';
|
||||
import {z} from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage,} from '@/components/ui/form';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from '@/components/ui/select';
|
||||
import {Textarea} from '@/components/ui/textarea';
|
||||
import type {ProxyRouteItem} from '@/lib/services/openflare';
|
||||
import {NodeService, PagesService} from '@/lib/services/openflare';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import type { ProxyRouteItem } from '@/lib/services/openflare';
|
||||
import { NodeService, PagesService } from '@/lib/services/openflare';
|
||||
|
||||
import {
|
||||
customHeadersToText,
|
||||
@@ -21,9 +35,9 @@ import {
|
||||
parseOriginUrls,
|
||||
validateOriginHost,
|
||||
} from '../../components/helpers';
|
||||
import {proxyRouteFormIds} from '../helpers';
|
||||
import {useRouteSectionSave} from '../hooks/use-route-section-save';
|
||||
import {SectionShell} from './section-shell';
|
||||
import { proxyRouteFormIds } from '../helpers';
|
||||
import { useRouteSectionSave } from '../hooks/use-route-section-save';
|
||||
import { SectionShell } from './section-shell';
|
||||
|
||||
const reverseProxySchema = z
|
||||
.object({
|
||||
@@ -86,7 +100,9 @@ const reverseProxySchema = z
|
||||
});
|
||||
}
|
||||
|
||||
const { error: headerError } = parseCustomHeadersText(value.custom_headers_text);
|
||||
const { error: headerError } = parseCustomHeadersText(
|
||||
value.custom_headers_text,
|
||||
);
|
||||
if (headerError) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
@@ -104,8 +120,16 @@ interface ProxySectionProps {
|
||||
onSavingChange?: (saving: boolean) => void;
|
||||
}
|
||||
|
||||
export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySectionProps) {
|
||||
const { saving, save } = useRouteSectionSave(route, onRouteUpdate, onSavingChange);
|
||||
export function ProxySection({
|
||||
route,
|
||||
onRouteUpdate,
|
||||
onSavingChange,
|
||||
}: ProxySectionProps) {
|
||||
const { saving, save } = useRouteSectionSave(
|
||||
route,
|
||||
onRouteUpdate,
|
||||
onSavingChange,
|
||||
);
|
||||
|
||||
const tunnelsQuery = useQuery({
|
||||
queryKey: ['openflare', 'nodes'],
|
||||
@@ -134,7 +158,9 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
tunnel_target_addr: route.tunnel_target_addr || '',
|
||||
tunnel_target_protocol:
|
||||
(route.tunnel_target_protocol as 'http' | 'https') || 'http',
|
||||
pages_project_id: route.pages_project_id ? String(route.pages_project_id) : '',
|
||||
pages_project_id: route.pages_project_id
|
||||
? String(route.pages_project_id)
|
||||
: '',
|
||||
custom_headers_text: customHeadersToText(route.custom_header_list),
|
||||
},
|
||||
});
|
||||
@@ -148,7 +174,9 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
tunnel_target_addr: route.tunnel_target_addr || '',
|
||||
tunnel_target_protocol:
|
||||
(route.tunnel_target_protocol as 'http' | 'https') || 'http',
|
||||
pages_project_id: route.pages_project_id ? String(route.pages_project_id) : '',
|
||||
pages_project_id: route.pages_project_id
|
||||
? String(route.pages_project_id)
|
||||
: '',
|
||||
custom_headers_text: customHeadersToText(route.custom_header_list),
|
||||
});
|
||||
}, [form, route]);
|
||||
@@ -157,15 +185,15 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
|
||||
return (
|
||||
<SectionShell
|
||||
title="反向代理"
|
||||
description="配置请求回源上游的策略与地址。"
|
||||
title='反向代理'
|
||||
description='配置请求回源上游的策略与地址。'
|
||||
formId={proxyRouteFormIds.proxy}
|
||||
saving={saving}
|
||||
>
|
||||
<Form {...form}>
|
||||
<form
|
||||
id={proxyRouteFormIds.proxy}
|
||||
className="space-y-5"
|
||||
className='space-y-5'
|
||||
onSubmit={form.handleSubmit(async (values) => {
|
||||
let originUrl = '';
|
||||
let originScheme: 'http' | 'https' = 'http';
|
||||
@@ -194,7 +222,9 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
originPort = '80';
|
||||
}
|
||||
|
||||
const { headers } = parseCustomHeadersText(values.custom_headers_text);
|
||||
const { headers } = parseCustomHeadersText(
|
||||
values.custom_headers_text,
|
||||
);
|
||||
|
||||
await save(
|
||||
{
|
||||
@@ -213,9 +243,13 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
? Number(values.tunnel_id)
|
||||
: null,
|
||||
tunnel_target_addr:
|
||||
values.upstream_type === 'tunnel' ? values.tunnel_target_addr : '',
|
||||
values.upstream_type === 'tunnel'
|
||||
? values.tunnel_target_addr
|
||||
: '',
|
||||
tunnel_target_protocol:
|
||||
values.upstream_type === 'tunnel' ? values.tunnel_target_protocol : '',
|
||||
values.upstream_type === 'tunnel'
|
||||
? values.tunnel_target_protocol
|
||||
: '',
|
||||
pages_project_id:
|
||||
values.upstream_type === 'pages' && values.pages_project_id
|
||||
? Number(values.pages_project_id)
|
||||
@@ -227,11 +261,11 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="upstream_type"
|
||||
name='upstream_type'
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-3">
|
||||
<FormItem className='space-y-3'>
|
||||
<FormLabel>回源方式</FormLabel>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<div className='flex flex-wrap gap-4'>
|
||||
{(
|
||||
[
|
||||
['direct', '直连上游'],
|
||||
@@ -239,15 +273,18 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
['pages', 'Pages 静态站点'],
|
||||
] as const
|
||||
).map(([value, label]) => (
|
||||
<label key={value} className="flex cursor-pointer items-center gap-2 text-sm">
|
||||
<label
|
||||
key={value}
|
||||
className='flex cursor-pointer items-center gap-2 text-sm'
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
type='radio'
|
||||
value={value}
|
||||
checked={field.value === value}
|
||||
onChange={() => field.onChange(value)}
|
||||
className="size-4 accent-primary"
|
||||
className='size-4 accent-primary'
|
||||
/>
|
||||
<Label className="font-normal">{label}</Label>
|
||||
<Label className='font-normal'>{label}</Label>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
@@ -259,13 +296,13 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
{upstreamType === 'direct' ? (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="origin_urls_text"
|
||||
name='origin_urls_text'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>上游地址</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="min-h-40 font-mono text-xs"
|
||||
className='min-h-40 font-mono text-xs'
|
||||
placeholder={
|
||||
'https://origin-a.internal:443\nhttps://origin-b.internal:443'
|
||||
}
|
||||
@@ -273,7 +310,9 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
每行一个完整 URL。第一行作为主回源,多上游模式请保持相同协议且不要包含 path 或 query。
|
||||
每行一个完整
|
||||
URL。第一行作为主回源,多上游模式请保持相同协议且不要包含
|
||||
path 或 query。
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -282,29 +321,37 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
) : null}
|
||||
|
||||
{upstreamType === 'tunnel' ? (
|
||||
<div className="space-y-4 rounded-lg border border-dashed bg-muted/30 p-4">
|
||||
<div className='space-y-4 rounded-lg border border-dashed bg-muted/30 p-4'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tunnel_id"
|
||||
name='tunnel_id'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>选择内网穿透隧道</FormLabel>
|
||||
<Select value={field.value || 'none'} onValueChange={(value) => field.onChange(value === 'none' ? '' : value)}>
|
||||
<Select
|
||||
value={field.value || 'none'}
|
||||
onValueChange={(value) =>
|
||||
field.onChange(value === 'none' ? '' : value)
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择..." />
|
||||
<SelectValue placeholder='请选择...' />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">请选择...</SelectItem>
|
||||
<SelectItem value='none'>请选择...</SelectItem>
|
||||
{tunnelClients.map((tunnel) => (
|
||||
<SelectItem key={tunnel.id} value={String(tunnel.id)}>
|
||||
{tunnel.name} ({tunnel.status === 'online' ? '在线' : '离线'})
|
||||
{tunnel.name} (
|
||||
{tunnel.status === 'online' ? '在线' : '离线'})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>将请求转发到该隧道连接的客户端节点。</FormDescription>
|
||||
<FormDescription>
|
||||
将请求转发到该隧道连接的客户端节点。
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -312,7 +359,7 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tunnel_target_protocol"
|
||||
name='tunnel_target_protocol'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>内网服务协议</FormLabel>
|
||||
@@ -323,8 +370,8 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="http">HTTP</SelectItem>
|
||||
<SelectItem value="https">HTTPS</SelectItem>
|
||||
<SelectItem value='http'>HTTP</SelectItem>
|
||||
<SelectItem value='https'>HTTPS</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
@@ -334,14 +381,16 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tunnel_target_addr"
|
||||
name='tunnel_target_addr'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>内网服务地址</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="127.0.0.1:8080" {...field} />
|
||||
<Input placeholder='127.0.0.1:8080' {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>例如: 127.0.0.1:8080 或 192.168.1.10:80</FormDescription>
|
||||
<FormDescription>
|
||||
例如: 127.0.0.1:8080 或 192.168.1.10:80
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -350,29 +399,39 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
) : null}
|
||||
|
||||
{upstreamType === 'pages' ? (
|
||||
<div className="rounded-lg border border-dashed bg-muted/30 p-4">
|
||||
<div className='rounded-lg border border-dashed bg-muted/30 p-4'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pages_project_id"
|
||||
name='pages_project_id'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>选择 Pages 项目</FormLabel>
|
||||
<Select value={field.value || 'none'} onValueChange={(value) => field.onChange(value === 'none' ? '' : value)}>
|
||||
<Select
|
||||
value={field.value || 'none'}
|
||||
onValueChange={(value) =>
|
||||
field.onChange(value === 'none' ? '' : value)
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择..." />
|
||||
<SelectValue placeholder='请选择...' />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">请选择...</SelectItem>
|
||||
<SelectItem value='none'>请选择...</SelectItem>
|
||||
{pagesProjects.map((project) => (
|
||||
<SelectItem key={project.id} value={String(project.id)}>
|
||||
<SelectItem
|
||||
key={project.id}
|
||||
value={String(project.id)}
|
||||
>
|
||||
{project.name} ({project.slug})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>仅显示已启用且已有激活部署的 Pages 项目。</FormDescription>
|
||||
<FormDescription>
|
||||
仅显示已启用且已有激活部署的 Pages 项目。
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -382,14 +441,16 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="origin_host"
|
||||
name='origin_host'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Origin Host Header</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="origin.example.internal" {...field} />
|
||||
<Input placeholder='origin.example.internal' {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>留空时默认透传访问域名 $host。</FormDescription>
|
||||
<FormDescription>
|
||||
留空时默认透传访问域名 $host。
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -397,13 +458,13 @@ export function ProxySection({ route, onRouteUpdate, onSavingChange }: ProxySect
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="custom_headers_text"
|
||||
name='custom_headers_text'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>自定义请求头</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="min-h-32 font-mono text-xs"
|
||||
className='min-h-32 font-mono text-xs'
|
||||
placeholder={'X-Trace-Id: $request_id\nX-Site: marketing'}
|
||||
{...field}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user