mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-13 10:26:38 +08:00
feat(waf): complete composable rule orchestration
Add the React Flow rule editor, ordered graph APIs and runtime DAG execution.\n\nPublish rules only on OpenResty reload and reconcile checksum-driven IP group snapshots in bounded shared memory.
This commit is contained in:
@@ -22,33 +22,25 @@ import {EmptyStateWithBorder} from '@/components/layout/empty';
|
||||
import {ErrorInline} from '@/components/layout/error';
|
||||
import {LoadingStateWithBorder} from '@/components/layout/loading';
|
||||
import type {WAFRule} from '@/lib/services/openflare';
|
||||
import {ProxyRouteService, WafService} from '@/lib/services/openflare';
|
||||
import {WafService} from '@/lib/services/openflare';
|
||||
|
||||
import {CreateRuleDialog} from './components/create-rule-dialog';
|
||||
import {getErrorMessage} from './components/helpers';
|
||||
import {RuleGroupsTable} from './components/rule-groups-table';
|
||||
import {SiteBindingSheet} from './components/site-binding-sheet';
|
||||
|
||||
const ruleGroupsQueryKey = ['openflare', 'waf', 'rule-groups'];
|
||||
const routesQueryKey = ['openflare', 'proxy-routes'];
|
||||
|
||||
export default function WafPage() {
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [deleteTarget, setDeleteTarget] = useState<WAFRule | null>(null);
|
||||
const [bindingGroup, setBindingGroup] = useState<WAFRule | null>(null);
|
||||
|
||||
const groupsQuery = useQuery({
|
||||
queryKey: ruleGroupsQueryKey,
|
||||
queryFn: () => WafService.listRuleGroups(),
|
||||
});
|
||||
|
||||
const routesQuery = useQuery({
|
||||
queryKey: routesQueryKey,
|
||||
queryFn: () => ProxyRouteService.list(),
|
||||
});
|
||||
|
||||
const invalidate = async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ruleGroupsQueryKey }),
|
||||
@@ -80,26 +72,13 @@ export default function WafPage() {
|
||||
},
|
||||
});
|
||||
|
||||
const bindMutation = useMutation({
|
||||
mutationFn: ({ id, ids }: { id: number; ids: number[] }) =>
|
||||
WafService.updateRuleGroupSites(id, ids),
|
||||
onSuccess: async () => {
|
||||
toast.success('规则组应用范围已更新');
|
||||
setBindingGroup(null);
|
||||
await invalidate();
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(getErrorMessage(error));
|
||||
},
|
||||
});
|
||||
|
||||
const handleRefresh = () => {
|
||||
void queryClient.invalidateQueries({ queryKey: ruleGroupsQueryKey });
|
||||
};
|
||||
|
||||
const groups = groupsQuery.data ?? [];
|
||||
const loading = groupsQuery.isLoading || routesQuery.isLoading;
|
||||
const error = groupsQuery.error ?? routesQuery.error ?? null;
|
||||
const loading = groupsQuery.isLoading;
|
||||
const error = groupsQuery.error ?? null;
|
||||
|
||||
return (
|
||||
<div className="w-full py-6 px-1 space-y-6">
|
||||
@@ -162,7 +141,6 @@ export default function WafPage() {
|
||||
groups={groups}
|
||||
onEdit={(rule) => router.push(`/waf/rules/editor?id=${rule.id}`)}
|
||||
onDelete={setDeleteTarget}
|
||||
onBindSites={setBindingGroup}
|
||||
/>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -177,19 +155,6 @@ export default function WafPage() {
|
||||
}}
|
||||
/>
|
||||
|
||||
<SiteBindingSheet
|
||||
group={bindingGroup}
|
||||
routes={routesQuery.data ?? []}
|
||||
open={Boolean(bindingGroup)}
|
||||
pending={bindMutation.isPending}
|
||||
onOpenChange={(open) => !open && setBindingGroup(null)}
|
||||
onSave={(ids) => {
|
||||
if (bindingGroup) {
|
||||
bindMutation.mutate({ id: bindingGroup.id, ids });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<AlertDialog
|
||||
open={Boolean(deleteTarget)}
|
||||
onOpenChange={(open) => !open && setDeleteTarget(null)}
|
||||
|
||||
Reference in New Issue
Block a user