+
+
+
+ setDraft((current) => ({
+ ...current,
+ name: event.target.value,
+ }))
+ }
+ />
+
+
+
+ setDraft((current) => ({
+ ...current,
+ type: event.target.value as WAFIPGroupType,
+ }))
+ }
+ >
+
+
+
+
+
+
+ setDraft((current) => ({ ...current, enabled: checked }))
+ }
+ />
+
+
+ setDraft((current) => ({
+ ...current,
+ remark: event.target.value,
+ }))
+ }
+ />
+
+
+
+ {draft.type === 'subscription' ? (
+
+
+
+ setDraft((current) => ({
+ ...current,
+ subscription_url: event.target.value,
+ }))
+ }
+ />
+
+
+
+ setDraft((current) => ({
+ ...current,
+ subscription_format: event.target
+ .value as WAFIPGroupSubscriptionFormat,
+ }))
+ }
+ >
+
+
+
+
+
+
+ setDraft((current) => ({
+ ...current,
+ sync_interval_minutes: Number(event.target.value),
+ }))
+ }
+ />
+
+
+
+ setDraft((current) => ({
+ ...current,
+ subscription_mapping_rule: event.target.value,
+ }))
+ }
+ />
+
+
+ ) : null}
+
+ {draft.type === 'automatic' ? (
+
+
+ setDraft((current) => ({
+ ...current,
+ auto_config_text: event.target.value,
+ }))
+ }
+ />
+
+ ) : (
+
+
+ setDraft((current) => ({
+ ...current,
+ ip_list_text: event.target.value,
+ }))
+ }
+ />
+
+ )}
+
+ {selectedGroup ? (
+
+
+ {selectedGroup.last_sync_status
+ ? `${selectedGroup.last_sync_status}: ${selectedGroup.last_sync_message}`
+ : '尚无同步记录'}
+
+
{
+ if (
+ window.confirm(
+ `确认删除 IP 组 ${selectedGroup.name} 吗?`,
+ )
+ ) {
+ deleteMutation.mutate(selectedGroup.id);
+ }
+ }}
+ >
+
+ 删除
+
+
+ ) : null}
+
+
+
+
+ );
+}
diff --git a/openflare_server/web/features/waf/components/rule-entry-modal.tsx b/openflare_server/web/features/waf/components/rule-entry-modal.tsx
index 89b963c4..b8940436 100644
--- a/openflare_server/web/features/waf/components/rule-entry-modal.tsx
+++ b/openflare_server/web/features/waf/components/rule-entry-modal.tsx
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'react';
import { Search } from 'lucide-react';
import { AppModal } from '@/components/ui/app-modal';
+import type { WAFIPGroup } from '@/features/waf/types';
import {
PrimaryButton,
ResourceField,
@@ -9,11 +10,17 @@ import {
} from '@/features/shared/components/resource-primitives';
import { cn } from '@/lib/utils/cn';
import { normalizeItems } from './helpers';
-import type { CountryOption, RuleListType, RuleDimension, RuleModalState } from './types';
+import type {
+ CountryOption,
+ RuleListType,
+ RuleDimension,
+ RuleModalState,
+} from './types';
export function RuleEntryModal({
state,
countryOptions,
+ ipGroups,
pending,
onClose,
onChange,
@@ -21,6 +28,7 @@ export function RuleEntryModal({
}: {
state: RuleModalState;
countryOptions: CountryOption[];
+ ipGroups: WAFIPGroup[];
pending: boolean;
onClose: () => void;
onChange: (patch: Partial