diff --git a/frontend/src/pages/xray/routing/RoutingTab.css b/frontend/src/pages/xray/routing/RoutingTab.css index 1d3590f4d..33176d793 100644 --- a/frontend/src/pages/xray/routing/RoutingTab.css +++ b/frontend/src/pages/xray/routing/RoutingTab.css @@ -235,3 +235,7 @@ text-align: center; } +.rule-disabled { + opacity: 0.5; + filter: grayscale(1); +} diff --git a/frontend/src/pages/xray/routing/RoutingTab.tsx b/frontend/src/pages/xray/routing/RoutingTab.tsx index 783e03e99..6da51608b 100644 --- a/frontend/src/pages/xray/routing/RoutingTab.tsx +++ b/frontend/src/pages/xray/routing/RoutingTab.tsx @@ -58,6 +58,7 @@ export default function RoutingTab({ () => rules.map((rule, idx) => { const r: RuleRow = { key: idx }; + r.enabled = rule.enabled !== false; r.domain = arrJoin(rule.domain); r.ip = arrJoin(rule.ip); r.port = rule.port; @@ -185,6 +186,13 @@ export default function RoutingTab({ [list[idx + 1], list[idx]] = [list[idx], list[idx + 1]]; }); } + function toggleRule(idx: number, enabled: boolean) { + mutate((tt) => { + const list = tt.routing?.rules; + if (!list || !list[idx]) return; + list[idx].enabled = enabled; + }); + } function onHandlePointerDown(idx: number, ev: React.PointerEvent) { if (ev.button != null && ev.button !== 0) return; @@ -247,6 +255,7 @@ export default function RoutingTab({ moveUp, moveDown, confirmDelete, + toggleRule, }); const tableScrollX = desktopColumns.reduce((sum, c) => { @@ -289,6 +298,7 @@ export default function RoutingTab({ moveUp={moveUp} moveDown={moveDown} confirmDelete={confirmDelete} + toggleRule={toggleRule} /> ) : ( void; moveDown: (idx: number) => void; confirmDelete: (idx: number) => void; + toggleRule: (idx: number, enabled: boolean) => void; } export default function RuleCardList({ @@ -36,6 +37,7 @@ export default function RuleCardList({ moveUp, moveDown, confirmDelete, + toggleRule, }: RuleCardListProps) { const { t } = useTranslation(); const { data: inboundOptions } = useInboundOptions(); @@ -50,7 +52,9 @@ export default function RuleCardList({ key={rule.key} className={`rule-card ${draggedIndex === index ? 'row-dragging' : ''} ${ dropTargetIndex === index && draggedIndex != null && index < draggedIndex ? 'drop-before' : '' - } ${dropTargetIndex === index && draggedIndex != null && index > draggedIndex ? 'drop-after' : ''}`} + } ${dropTargetIndex === index && draggedIndex != null && index > draggedIndex ? 'drop-after' : ''} ${ + rule.enabled === false ? 'rule-disabled' : '' + }`} data-row-key={index} >
@@ -72,6 +76,13 @@ export default function RuleCardList({ >
diff --git a/frontend/src/pages/xray/routing/RuleFormModal.tsx b/frontend/src/pages/xray/routing/RuleFormModal.tsx index eafd1547e..a92ce665d 100644 --- a/frontend/src/pages/xray/routing/RuleFormModal.tsx +++ b/frontend/src/pages/xray/routing/RuleFormModal.tsx @@ -5,9 +5,10 @@ import { PlusOutlined, MinusOutlined, QuestionCircleOutlined } from '@ant-design import { InputAddon } from '@/components/ui'; import { useInboundOptions } from '@/api/queries/useInboundOptions'; import { RuleFormSchema, type RuleFormValues } from '@/schemas/xray'; -import { buildRemarkByTag, formatInboundTag } from './helpers'; +import { buildRemarkByTag, formatInboundTag, isApiRule } from './helpers'; export interface RoutingRule { + enabled?: boolean; type?: string; domain?: string | string[]; ip?: string | string[]; @@ -38,6 +39,7 @@ interface RuleFormModalProps { type FormState = RuleFormValues; const initialForm = (): FormState => ({ + enabled: true, domain: '', ip: '', port: '', @@ -81,6 +83,7 @@ export default function RuleFormModal({ if (!open) return; if (rule) { setForm({ + enabled: rule.enabled !== false, domain: Array.isArray(rule.domain) ? rule.domain.join(',') : rule.domain || '', ip: Array.isArray(rule.ip) ? rule.ip.join(',') : rule.ip || '', port: rule.port || '', @@ -109,6 +112,7 @@ export default function RuleFormModal({ const v = validated.data; const built: Record = { type: 'field', + enabled: v.enabled, domain: csv(v.domain), ip: csv(v.ip), port: v.port, @@ -151,6 +155,18 @@ export default function RuleFormModal({ onCancel={onClose} >
+ +