add position to add rule
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
This commit is contained in:
@@ -320,13 +320,48 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
chain = chainVal;
|
||||
}
|
||||
|
||||
// compute insertion position if user selected an "insert after" handle
|
||||
let positionToken = '';
|
||||
if (
|
||||
vals.insertAfterHandle &&
|
||||
tableSelect &&
|
||||
tableSelect !== '__manual__' &&
|
||||
chain &&
|
||||
chain !== '__manual_chain__'
|
||||
) {
|
||||
// find index of the selected handle in current tables state
|
||||
try {
|
||||
const [f, n] = String(tableSelect).split(':');
|
||||
const tbl = tables.find((t) => t.family === f && t.name === n);
|
||||
if (tbl) {
|
||||
const ch = tbl.chains.find((c) => c.name === chain);
|
||||
if (ch) {
|
||||
const idx = ch.rules.findIndex((r) => String(r.handle) === String(vals.insertAfterHandle));
|
||||
if (idx >= 0) {
|
||||
const pos = idx + 1; // insert after -> index+1
|
||||
positionToken = ` position ${pos}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
positionToken = '';
|
||||
}
|
||||
}
|
||||
|
||||
const short = textFromExpr(expr);
|
||||
const cmd = `add rule ${family} ${tableName} ${chain} ${short}`.trim();
|
||||
const cmd = `add rule ${family} ${tableName} ${chain}${positionToken} ${short}`.trim();
|
||||
setCmdPreview(cmd);
|
||||
|
||||
const reqObj = { family, table: tableName, chain, expr };
|
||||
const reqObj: any = { family, table: tableName, chain, expr };
|
||||
if (positionToken) {
|
||||
// extract numeric pos and include in request body
|
||||
const m = positionToken.match(/position\s+(\d+)/);
|
||||
if (m) {
|
||||
reqObj.position = Number(m[1]);
|
||||
}
|
||||
}
|
||||
setRequestJsonPreview(reqObj);
|
||||
}, [form]);
|
||||
}, [form, tables]);
|
||||
|
||||
useEffect(() => {
|
||||
updatePreviews();
|
||||
@@ -377,9 +412,33 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
}
|
||||
|
||||
const expr = buildExprFromValues(values);
|
||||
|
||||
// compute optional position from insertAfterHandle
|
||||
const reqObj: any = { family, table: tableName, chain, expr };
|
||||
if (
|
||||
values.insertAfterHandle &&
|
||||
tableSelect &&
|
||||
tableSelect !== '__manual__' &&
|
||||
chain &&
|
||||
chain !== '__manual_chain__'
|
||||
) {
|
||||
// locate index of handle and set position = index+1
|
||||
const [f, n] = String(tableSelect).split(':');
|
||||
const tbl = tables.find((t) => t.family === f && t.name === n);
|
||||
if (tbl) {
|
||||
const ch = tbl.chains.find((c) => c.name === chain);
|
||||
if (ch) {
|
||||
const idx = ch.rules.findIndex((r) => String(r.handle) === String(values.insertAfterHandle));
|
||||
if (idx >= 0) {
|
||||
reqObj.position = idx + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const textual = textFromExpr(expr);
|
||||
const cmd = `add rule ${family} ${tableName} ${chain} ${textual}`.trim();
|
||||
const reqObj = { family, table: tableName, chain, expr };
|
||||
const posStr = reqObj.position !== undefined ? ` position ${reqObj.position}` : '';
|
||||
const cmd = `add rule ${family} ${tableName} ${chain}${posStr} ${textual}`.trim();
|
||||
|
||||
Modal.confirm({
|
||||
title: 'Create rule (JSON)',
|
||||
@@ -409,7 +468,7 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
// refresh tables/chains after successful creation
|
||||
await loadTables();
|
||||
if (onCreated) await onCreated();
|
||||
form.resetFields(['advanced']);
|
||||
form.resetFields(['advanced', 'insertAfterHandle']);
|
||||
} else {
|
||||
message.error(`Create failed: ${res?.stderr ?? 'unknown error'}`);
|
||||
}
|
||||
@@ -426,7 +485,7 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
);
|
||||
await loadTables();
|
||||
if (onCreated) await onCreated();
|
||||
form.resetFields(['advanced']);
|
||||
form.resetFields(['advanced', 'insertAfterHandle']);
|
||||
} else {
|
||||
const errMsg = typeof stderr === 'string' ? stderr : JSON.stringify(stderr);
|
||||
message.error(`Create failed: ${errMsg}`);
|
||||
@@ -445,7 +504,7 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
},
|
||||
});
|
||||
},
|
||||
[form, onCreated],
|
||||
[form, onCreated, tables],
|
||||
);
|
||||
|
||||
// prepare chain options for currently selected table
|
||||
@@ -478,6 +537,24 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
);
|
||||
}, [form, tables]);
|
||||
|
||||
// build insert-after options for currently selected table+chain
|
||||
const insertAfterOptions = useMemo(() => {
|
||||
const ts = form.getFieldValue('tableSelect');
|
||||
const cs = form.getFieldValue('chainSelect');
|
||||
if (!ts || ts === '__manual__' || !cs || cs === '__manual_chain__') return [];
|
||||
const [f, n] = String(ts).split(':');
|
||||
const tbl = tables.find((t) => t.family === f && t.name === n);
|
||||
if (!tbl) return [];
|
||||
const ch = tbl.chains.find((c) => c.name === cs);
|
||||
if (!ch || !Array.isArray(ch.rules)) return [];
|
||||
return ch.rules
|
||||
.filter((r: any) => r && r.handle !== undefined && r.handle !== null)
|
||||
.map((r: any) => ({
|
||||
value: r.handle,
|
||||
label: `#${r.handle} — ${r.text ?? (typeof r.expr === 'string' ? r.expr : JSON.stringify(r.expr || r).slice(0, 120))}`,
|
||||
}));
|
||||
}, [form, tables]);
|
||||
|
||||
return (
|
||||
<Card style={{ maxWidth: 980 }}>
|
||||
<Row justify="space-between" align="middle">
|
||||
@@ -569,6 +646,41 @@ export const RuleBuilder: React.FC<RuleBuilderProps> = ({ onCreated }) => {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* Insert-after control */}
|
||||
{form.getFieldValue('tableSelect') !== '__manual__' &&
|
||||
form.getFieldValue('chainSelect') &&
|
||||
form.getFieldValue('chainSelect') !== '__manual_chain__' && (
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={12}>
|
||||
<Form.Item
|
||||
name="insertAfterHandle"
|
||||
label="Insert after (optional)"
|
||||
help="Pick an existing rule handle to insert *after*. If left empty the rule will be appended."
|
||||
>
|
||||
<Select allowClear placeholder="Append (no insert-after)">
|
||||
{insertAfterOptions.length === 0 ? (
|
||||
<Option value="__none__" disabled>
|
||||
(no rules available)
|
||||
</Option>
|
||||
) : (
|
||||
insertAfterOptions.map((o: any) => (
|
||||
<Option key={String(o.value)} value={o.value}>
|
||||
{o.label}
|
||||
</Option>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} style={{ display: 'flex', alignItems: 'flex-end' }}>
|
||||
<Text type="secondary">
|
||||
Use when you want the new rule to appear right after a known handle. Refresh tables to see latest
|
||||
handles.
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
{/* Protocol / addresses */}
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={8}>
|
||||
|
||||
Reference in New Issue
Block a user