mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-07 16:16:37 +08:00
fix(waf): 调整编辑器返回与格式化布局按钮位置
返回置于标题上方;格式化布局移至保存按钮左侧。
This commit is contained in:
@@ -25,10 +25,9 @@ import {
|
|||||||
type NodeChange,
|
type NodeChange,
|
||||||
type ReactFlowInstance,
|
type ReactFlowInstance,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
import { AlignHorizontalSpaceAround, Trash2 } from 'lucide-react';
|
import { Trash2 } from 'lucide-react';
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import type { WAFRuleEdge, WAFRuleGraph } from '@/lib/services/openflare';
|
import type { WAFRuleEdge, WAFRuleGraph } from '@/lib/services/openflare';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
@@ -39,7 +38,6 @@ import {
|
|||||||
isConnectionAllowed,
|
isConnectionAllowed,
|
||||||
isPersistentEdgeChange,
|
isPersistentEdgeChange,
|
||||||
} from './editor-behavior';
|
} from './editor-behavior';
|
||||||
import { layoutRuleGraph } from './graph-layout';
|
|
||||||
import {
|
import {
|
||||||
type GraphIssue,
|
type GraphIssue,
|
||||||
removeEdgeFromGraph,
|
removeEdgeFromGraph,
|
||||||
@@ -328,18 +326,6 @@ export function RuleFlowCanvas({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const formatLayout = useCallback(() => {
|
|
||||||
const next = layoutRuleGraph(graph);
|
|
||||||
onGraphChange(next);
|
|
||||||
setContextMenu(null);
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
void instance.current?.fitView({
|
|
||||||
...initialFitViewOptions,
|
|
||||||
duration: 280,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [graph, onGraphChange]);
|
|
||||||
|
|
||||||
const contextNode =
|
const contextNode =
|
||||||
contextMenu?.kind === 'node'
|
contextMenu?.kind === 'node'
|
||||||
? graph.nodes.find((node) => node.id === contextMenu.id)
|
? graph.nodes.find((node) => node.id === contextMenu.id)
|
||||||
@@ -357,18 +343,8 @@ export function RuleFlowCanvas({
|
|||||||
className='relative min-w-0 flex-1 bg-muted/20'
|
className='relative min-w-0 flex-1 bg-muted/20'
|
||||||
onContextMenu={suppressBrowserContextMenu}
|
onContextMenu={suppressBrowserContextMenu}
|
||||||
>
|
>
|
||||||
<div className='absolute left-4 top-4 z-10 flex flex-wrap items-center gap-2 rounded-lg border bg-background/95 p-2 shadow-sm backdrop-blur'>
|
<div className='absolute left-4 top-4 z-10 rounded-lg border bg-background/95 p-2 shadow-sm backdrop-blur'>
|
||||||
<NodeLibrary />
|
<NodeLibrary />
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
variant='outline'
|
|
||||||
size='sm'
|
|
||||||
title='自动整理节点与连线布局'
|
|
||||||
onClick={formatLayout}
|
|
||||||
>
|
|
||||||
<AlignHorizontalSpaceAround data-icon='inline-start' />
|
|
||||||
格式化布局
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
|
import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ArrowLeft, GitBranch, Save } from 'lucide-react';
|
import {
|
||||||
|
AlignHorizontalSpaceAround,
|
||||||
|
ArrowLeft,
|
||||||
|
GitBranch,
|
||||||
|
Save,
|
||||||
|
} from 'lucide-react';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
@@ -20,14 +25,15 @@ import {
|
|||||||
} from '@/lib/services';
|
} from '@/lib/services';
|
||||||
|
|
||||||
import { getErrorMessage } from '../../components/helpers';
|
import { getErrorMessage } from '../../components/helpers';
|
||||||
import { validateGraph } from './components/graph-validation';
|
|
||||||
import { NodeProperties } from './components/node-properties';
|
|
||||||
import { RuleFlowCanvas } from './components/rule-flow-canvas';
|
|
||||||
import { UnsavedChanges } from './components/unsaved-changes';
|
|
||||||
import {
|
import {
|
||||||
findGraphErrorTarget,
|
findGraphErrorTarget,
|
||||||
type GraphErrorTarget,
|
type GraphErrorTarget,
|
||||||
} from './components/editor-behavior';
|
} from './components/editor-behavior';
|
||||||
|
import { layoutRuleGraph } from './components/graph-layout';
|
||||||
|
import { validateGraph } from './components/graph-validation';
|
||||||
|
import { NodeProperties } from './components/node-properties';
|
||||||
|
import { RuleFlowCanvas } from './components/rule-flow-canvas';
|
||||||
|
import { UnsavedChanges } from './components/unsaved-changes';
|
||||||
|
|
||||||
export default function WAFRuleEditorPage() {
|
export default function WAFRuleEditorPage() {
|
||||||
return (
|
return (
|
||||||
@@ -160,6 +166,10 @@ function EditorContent() {
|
|||||||
},
|
},
|
||||||
[changeGraph, graph],
|
[changeGraph, graph],
|
||||||
);
|
);
|
||||||
|
const formatLayout = useCallback(() => {
|
||||||
|
if (!graph) return;
|
||||||
|
changeGraph(layoutRuleGraph(graph));
|
||||||
|
}, [changeGraph, graph]);
|
||||||
const leave = () => {
|
const leave = () => {
|
||||||
if (!dirty || window.confirm('存在未保存的更改,确定离开吗?'))
|
if (!dirty || window.confirm('存在未保存的更改,确定离开吗?'))
|
||||||
router.push('/waf');
|
router.push('/waf');
|
||||||
@@ -186,58 +196,72 @@ function EditorContent() {
|
|||||||
return (
|
return (
|
||||||
<div className='flex h-[calc(100dvh-8rem)] w-full flex-col px-1 py-6'>
|
<div className='flex h-[calc(100dvh-8rem)] w-full flex-col px-1 py-6'>
|
||||||
<UnsavedChanges dirty={dirty} />
|
<UnsavedChanges dirty={dirty} />
|
||||||
<header className='mb-4 flex items-center justify-between gap-4'>
|
<header className='mb-4 flex flex-col gap-3'>
|
||||||
<div className='flex min-w-0 items-center gap-2'>
|
<div>
|
||||||
<GitBranch className='size-5 text-primary' />
|
<Button variant='outline' size='sm' onClick={leave}>
|
||||||
<h1 className='text-2xl font-semibold tracking-tight'>
|
|
||||||
{ruleQuery.data.name}
|
|
||||||
</h1>
|
|
||||||
<Badge variant={ruleQuery.data.enabled ? 'default' : 'secondary'}>
|
|
||||||
{ruleQuery.data.enabled ? '已启用' : '已停用'}
|
|
||||||
</Badge>
|
|
||||||
<Badge variant={issues.length === 0 ? 'outline' : 'destructive'}>
|
|
||||||
{issues.length === 0 ? '图校验通过' : `${issues.length} 个问题`}
|
|
||||||
</Badge>
|
|
||||||
{dirty && <Badge variant='secondary'>未保存</Badge>}
|
|
||||||
</div>
|
|
||||||
<div className='flex shrink-0 items-center gap-2'>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<Switch
|
|
||||||
id='rule-enabled'
|
|
||||||
checked={ruleQuery.data.enabled}
|
|
||||||
disabled={
|
|
||||||
dirty ||
|
|
||||||
issues.length > 0 ||
|
|
||||||
saveMutation.isPending ||
|
|
||||||
metaMutation.isPending
|
|
||||||
}
|
|
||||||
onCheckedChange={(enabled) => metaMutation.mutate(enabled)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor='rule-enabled'>启用规则</Label>
|
|
||||||
</div>
|
|
||||||
<Button variant='outline' onClick={leave}>
|
|
||||||
<ArrowLeft data-icon='inline-start' />
|
<ArrowLeft data-icon='inline-start' />
|
||||||
返回
|
返回规则组
|
||||||
</Button>
|
</Button>
|
||||||
{conflict && (
|
</div>
|
||||||
|
<div className='flex items-center justify-between gap-4'>
|
||||||
|
<div className='flex min-w-0 items-center gap-2'>
|
||||||
|
<GitBranch className='size-5 text-primary' />
|
||||||
|
<h1 className='text-2xl font-semibold tracking-tight'>
|
||||||
|
{ruleQuery.data.name}
|
||||||
|
</h1>
|
||||||
|
<Badge variant={ruleQuery.data.enabled ? 'default' : 'secondary'}>
|
||||||
|
{ruleQuery.data.enabled ? '已启用' : '已停用'}
|
||||||
|
</Badge>
|
||||||
|
<Badge variant={issues.length === 0 ? 'outline' : 'destructive'}>
|
||||||
|
{issues.length === 0 ? '图校验通过' : `${issues.length} 个问题`}
|
||||||
|
</Badge>
|
||||||
|
{dirty && <Badge variant='secondary'>未保存</Badge>}
|
||||||
|
</div>
|
||||||
|
<div className='flex shrink-0 items-center gap-2'>
|
||||||
|
<div className='flex items-center gap-2'>
|
||||||
|
<Switch
|
||||||
|
id='rule-enabled'
|
||||||
|
checked={ruleQuery.data.enabled}
|
||||||
|
disabled={
|
||||||
|
dirty ||
|
||||||
|
issues.length > 0 ||
|
||||||
|
saveMutation.isPending ||
|
||||||
|
metaMutation.isPending
|
||||||
|
}
|
||||||
|
onCheckedChange={(enabled) => metaMutation.mutate(enabled)}
|
||||||
|
/>
|
||||||
|
<Label htmlFor='rule-enabled'>启用规则</Label>
|
||||||
|
</div>
|
||||||
|
{conflict && (
|
||||||
|
<Button
|
||||||
|
variant='outline'
|
||||||
|
onClick={() => {
|
||||||
|
setDirty(false);
|
||||||
|
setConflict(false);
|
||||||
|
void ruleQuery.refetch();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
重新加载
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
|
type='button'
|
||||||
variant='outline'
|
variant='outline'
|
||||||
onClick={() => {
|
title='自动整理节点与连线布局'
|
||||||
setDirty(false);
|
disabled={!graph}
|
||||||
setConflict(false);
|
onClick={formatLayout}
|
||||||
void ruleQuery.refetch();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
重新加载
|
<AlignHorizontalSpaceAround data-icon='inline-start' />
|
||||||
|
格式化布局
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
<Button
|
||||||
<Button
|
disabled={!dirty || issues.length > 0 || saveMutation.isPending}
|
||||||
disabled={!dirty || issues.length > 0 || saveMutation.isPending}
|
onClick={() => saveMutation.mutate()}
|
||||||
onClick={() => saveMutation.mutate()}
|
>
|
||||||
>
|
<Save data-icon='inline-start' />
|
||||||
<Save data-icon='inline-start' />
|
{saveMutation.isPending ? '保存中...' : '保存'}
|
||||||
{saveMutation.isPending ? '保存中...' : '保存'}
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div className='flex min-h-0 flex-1 overflow-hidden rounded-xl border bg-background shadow-sm'>
|
<div className='flex min-h-0 flex-1 overflow-hidden rounded-xl border bg-background shadow-sm'>
|
||||||
|
|||||||
Reference in New Issue
Block a user