mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-12 02:06:37 +08:00
fix(waf): UA 检查说明改为问号悬浮提示
将屏蔽/匹配相关 FieldDescription 收敛为 CircleHelp Tooltip。
This commit is contained in:
@@ -25,9 +25,9 @@ it('hides match and block until UA check is enabled', () => {
|
|||||||
const { rerender } = render(
|
const { rerender } = render(
|
||||||
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
||||||
);
|
);
|
||||||
expect(screen.queryByLabelText('屏蔽常见爬虫 UA')).not.toBeInTheDocument();
|
expect(screen.queryByRole('switch', { name: /屏蔽常见爬虫/ })).not.toBeInTheDocument();
|
||||||
expect(screen.queryByLabelText('浏览器')).not.toBeInTheDocument();
|
expect(screen.queryByLabelText('浏览器')).not.toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByLabelText('开启 UA 检查'));
|
fireEvent.click(screen.getByRole('switch', { name: /开启 UA 检查/ }));
|
||||||
expect(onChange).toHaveBeenCalledWith(
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
config: expect.objectContaining({ require_ua: true }),
|
config: expect.objectContaining({ require_ua: true }),
|
||||||
@@ -40,11 +40,10 @@ it('hides match and block until UA check is enabled', () => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
expect(screen.getByLabelText('屏蔽常见爬虫 UA')).toBeInTheDocument();
|
expect(screen.getByRole('switch', { name: /屏蔽常见爬虫/ })).toBeInTheDocument();
|
||||||
expect(screen.getByLabelText('屏蔽非正常 UA')).toBeInTheDocument();
|
expect(screen.getByRole('switch', { name: /屏蔽非正常/ })).toBeInTheDocument();
|
||||||
expect(screen.getByLabelText('屏蔽自定义 UA')).toBeInTheDocument();
|
expect(screen.getByRole('switch', { name: /屏蔽自定义/ })).toBeInTheDocument();
|
||||||
expect(screen.getByText(/浏览器或操作系统分类为 Bot/)).toBeInTheDocument();
|
expect(screen.getAllByLabelText('说明').length).toBeGreaterThan(0);
|
||||||
expect(screen.getByText(/浏览器分类为 Other 或 Unknown/)).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('edits display name for configurable nodes', () => {
|
it('edits display name for configurable nodes', () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Settings2 } from 'lucide-react';
|
import { CircleHelp, Settings2 } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -27,6 +27,11 @@ import {
|
|||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@/components/ui/tooltip';
|
||||||
import type { WAFIPGroup, WAFRuleNode } from '@/lib/services/openflare';
|
import type { WAFIPGroup, WAFRuleNode } from '@/lib/services/openflare';
|
||||||
|
|
||||||
import { countryOptions, regionOptions, type GeoOption } from './geo-options';
|
import { countryOptions, regionOptions, type GeoOption } from './geo-options';
|
||||||
@@ -149,14 +154,13 @@ function PropertyFields({
|
|||||||
orientation='horizontal'
|
orientation='horizontal'
|
||||||
className='items-center justify-between'
|
className='items-center justify-between'
|
||||||
>
|
>
|
||||||
<div className='space-y-1'>
|
<FieldLabel
|
||||||
<FieldLabel htmlFor={`${node.id}-require-ua`}>
|
htmlFor={`${node.id}-require-ua`}
|
||||||
开启 UA 检查
|
className='flex items-center gap-1.5'
|
||||||
</FieldLabel>
|
>
|
||||||
<FieldDescription>
|
开启 UA 检查
|
||||||
开启后如果请求头不携带 UA 将返回 False
|
<FieldHelp tip='开启后如果请求头不携带 UA 将返回 False' />
|
||||||
</FieldDescription>
|
</FieldLabel>
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
id={`${node.id}-require-ua`}
|
id={`${node.id}-require-ua`}
|
||||||
checked={node.config.require_ua}
|
checked={node.config.require_ua}
|
||||||
@@ -170,30 +174,23 @@ function PropertyFields({
|
|||||||
<>
|
<>
|
||||||
<Separator />
|
<Separator />
|
||||||
<div className='space-y-3'>
|
<div className='space-y-3'>
|
||||||
<div className='space-y-1'>
|
<p className='flex items-center gap-1.5 text-xs font-medium text-muted-foreground'>
|
||||||
<p className='text-xs font-medium text-muted-foreground'>
|
屏蔽
|
||||||
屏蔽
|
<FieldHelp tip='命中返回 false,优先级高于匹配' />
|
||||||
</p>
|
</p>
|
||||||
<FieldDescription>
|
|
||||||
命中返回 false,优先级高于匹配
|
|
||||||
</FieldDescription>
|
|
||||||
</div>
|
|
||||||
<Field
|
<Field
|
||||||
orientation='horizontal'
|
orientation='horizontal'
|
||||||
className='items-start justify-between gap-3'
|
className='items-center justify-between gap-3'
|
||||||
>
|
>
|
||||||
<div className='space-y-1'>
|
<FieldLabel
|
||||||
<FieldLabel htmlFor={`${node.id}-block-bots`}>
|
htmlFor={`${node.id}-block-bots`}
|
||||||
屏蔽常见爬虫 UA
|
className='flex items-center gap-1.5'
|
||||||
</FieldLabel>
|
>
|
||||||
<FieldDescription>
|
屏蔽常见爬虫 UA
|
||||||
浏览器或操作系统分类为 Bot(含 bot / spider / crawler /
|
<FieldHelp tip='浏览器或操作系统分类为 Bot(含 bot / spider / crawler / slurp 等特征,如 Googlebot)' />
|
||||||
slurp 等特征,如 Googlebot)
|
</FieldLabel>
|
||||||
</FieldDescription>
|
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
id={`${node.id}-block-bots`}
|
id={`${node.id}-block-bots`}
|
||||||
className='mt-0.5'
|
|
||||||
checked={node.config.block_common_bots}
|
checked={node.config.block_common_bots}
|
||||||
onCheckedChange={(block_common_bots) =>
|
onCheckedChange={(block_common_bots) =>
|
||||||
onChange({
|
onChange({
|
||||||
@@ -205,20 +202,17 @@ function PropertyFields({
|
|||||||
</Field>
|
</Field>
|
||||||
<Field
|
<Field
|
||||||
orientation='horizontal'
|
orientation='horizontal'
|
||||||
className='items-start justify-between gap-3'
|
className='items-center justify-between gap-3'
|
||||||
>
|
>
|
||||||
<div className='space-y-1'>
|
<FieldLabel
|
||||||
<FieldLabel htmlFor={`${node.id}-block-abnormal`}>
|
htmlFor={`${node.id}-block-abnormal`}
|
||||||
屏蔽非正常 UA
|
className='flex items-center gap-1.5'
|
||||||
</FieldLabel>
|
>
|
||||||
<FieldDescription>
|
屏蔽非正常 UA
|
||||||
浏览器分类为 Other 或 Unknown(不含搜索引擎等爬虫
|
<FieldHelp tip='浏览器分类为 Other 或 Unknown(不含搜索引擎等爬虫 Bot,爬虫请用上方开关)' />
|
||||||
Bot,爬虫请用上方开关)
|
</FieldLabel>
|
||||||
</FieldDescription>
|
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
id={`${node.id}-block-abnormal`}
|
id={`${node.id}-block-abnormal`}
|
||||||
className='mt-0.5'
|
|
||||||
checked={node.config.block_abnormal_ua}
|
checked={node.config.block_abnormal_ua}
|
||||||
onCheckedChange={(block_abnormal_ua) =>
|
onCheckedChange={(block_abnormal_ua) =>
|
||||||
onChange({
|
onChange({
|
||||||
@@ -230,19 +224,17 @@ function PropertyFields({
|
|||||||
</Field>
|
</Field>
|
||||||
<Field
|
<Field
|
||||||
orientation='horizontal'
|
orientation='horizontal'
|
||||||
className='items-start justify-between gap-3'
|
className='items-center justify-between gap-3'
|
||||||
>
|
>
|
||||||
<div className='space-y-1'>
|
<FieldLabel
|
||||||
<FieldLabel htmlFor={`${node.id}-block-custom`}>
|
htmlFor={`${node.id}-block-custom`}
|
||||||
屏蔽自定义 UA
|
className='flex items-center gap-1.5'
|
||||||
</FieldLabel>
|
>
|
||||||
<FieldDescription>
|
屏蔽自定义 UA
|
||||||
原始 User-Agent 命中任一条正则时返回 false(Lua 模式语法)
|
<FieldHelp tip='原始 User-Agent 命中任一条正则时返回 false(Lua 模式语法)' />
|
||||||
</FieldDescription>
|
</FieldLabel>
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
id={`${node.id}-block-custom`}
|
id={`${node.id}-block-custom`}
|
||||||
className='mt-0.5'
|
|
||||||
checked={node.config.block_custom_ua}
|
checked={node.config.block_custom_ua}
|
||||||
onCheckedChange={(block_custom_ua) =>
|
onCheckedChange={(block_custom_ua) =>
|
||||||
onChange({
|
onChange({
|
||||||
@@ -254,8 +246,12 @@ function PropertyFields({
|
|||||||
</Field>
|
</Field>
|
||||||
{node.config.block_custom_ua && (
|
{node.config.block_custom_ua && (
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel htmlFor={`${node.id}-custom-patterns`}>
|
<FieldLabel
|
||||||
|
htmlFor={`${node.id}-custom-patterns`}
|
||||||
|
className='flex items-center gap-1.5'
|
||||||
|
>
|
||||||
自定义 UA 正则
|
自定义 UA 正则
|
||||||
|
<FieldHelp tip='每行一条 Lua 模式正则,命中任一条即 false;最多 32 条' />
|
||||||
</FieldLabel>
|
</FieldLabel>
|
||||||
<Textarea
|
<Textarea
|
||||||
id={`${node.id}-custom-patterns`}
|
id={`${node.id}-custom-patterns`}
|
||||||
@@ -275,9 +271,6 @@ function PropertyFields({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<FieldDescription>
|
|
||||||
每行一条 Lua 模式正则,命中任一条即 false;最多 32 条
|
|
||||||
</FieldDescription>
|
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -287,8 +280,12 @@ function PropertyFields({
|
|||||||
UA 匹配
|
UA 匹配
|
||||||
</p>
|
</p>
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel htmlFor={`${node.id}-match-mode`}>
|
<FieldLabel
|
||||||
|
htmlFor={`${node.id}-match-mode`}
|
||||||
|
className='flex items-center gap-1.5'
|
||||||
|
>
|
||||||
匹配模式
|
匹配模式
|
||||||
|
<FieldHelp tip='浏览器与操作系统两侧都有选择时生效' />
|
||||||
</FieldLabel>
|
</FieldLabel>
|
||||||
<Select
|
<Select
|
||||||
value={node.config.match_mode}
|
value={node.config.match_mode}
|
||||||
@@ -312,9 +309,6 @@ function PropertyFields({
|
|||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FieldDescription>
|
|
||||||
浏览器与操作系统两侧都有选择时生效
|
|
||||||
</FieldDescription>
|
|
||||||
</Field>
|
</Field>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
id={`${node.id}-browsers`}
|
id={`${node.id}-browsers`}
|
||||||
@@ -431,6 +425,26 @@ function PropertyFields({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FieldHelp({ tip }: { tip: string }) {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='inline-flex size-4 shrink-0 items-center justify-center text-muted-foreground transition-colors hover:text-foreground'
|
||||||
|
aria-label='说明'
|
||||||
|
onClick={(event) => event.preventDefault()}
|
||||||
|
>
|
||||||
|
<CircleHelp className='size-3.5' />
|
||||||
|
</button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side='top' className='max-w-56 text-xs'>
|
||||||
|
{tip}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function DisplayNameField({
|
function DisplayNameField({
|
||||||
node,
|
node,
|
||||||
onChange,
|
onChange,
|
||||||
|
|||||||
Reference in New Issue
Block a user