diff --git a/virtweb_backend/src/controllers/server_controller.rs b/virtweb_backend/src/controllers/server_controller.rs index d029059..5d69687 100644 --- a/virtweb_backend/src/controllers/server_controller.rs +++ b/virtweb_backend/src/controllers/server_controller.rs @@ -47,6 +47,7 @@ struct ServerConstraints { nwfilter_name_size: LenConstraints, nwfilter_comment_size: LenConstraints, nwfilter_priority: SLenConstraints, + nwfilter_selectors_count: LenConstraints, } pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder { @@ -89,6 +90,7 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder { min: -1000, max: 1000, }, + nwfilter_selectors_count: LenConstraints { min: 0, max: 1 }, }, }) } diff --git a/virtweb_frontend/src/api/ServerApi.ts b/virtweb_frontend/src/api/ServerApi.ts index 6ab909e..ac68612 100644 --- a/virtweb_frontend/src/api/ServerApi.ts +++ b/virtweb_frontend/src/api/ServerApi.ts @@ -25,6 +25,7 @@ export interface ServerConstraints { nwfilter_name_size: LenConstraint; nwfilter_comment_size: LenConstraint; nwfilter_priority: LenConstraint; + nwfilter_selectors_count: LenConstraint; } export interface LenConstraint { diff --git a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx new file mode 100644 index 0000000..0938e75 --- /dev/null +++ b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx @@ -0,0 +1,146 @@ +import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; +import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; +import DeleteIcon from "@mui/icons-material/Delete"; +import { + Button, + Card, + CardActions, + CardContent, + IconButton, +} from "@mui/material"; +import { NWFilterRule } from "../../api/NWFilterApi"; +import { EditSection } from "./EditSection"; +import { SelectInput } from "./SelectInput"; +import { TextInput } from "./TextInput"; +import { ServerApi } from "../../api/ServerApi"; + +export function NWFilterRules(p: { + editable: boolean; + rules: NWFilterRule[]; + onChange?: () => void; +}): React.ReactElement { + const addRule = () => { + p.rules.push({ + action: "drop", + direction: "inout", + selectors: [], + }); + p.onChange?.(); + }; + + const swapRules = (f: number, s: number) => { + const swap = p.rules[f]; + p.rules[f] = p.rules[s]; + p.rules[s] = swap; + p.onChange?.(); + }; + + const deleteRule = (num: number) => { + p.rules.splice(num, 1); + p.onChange?.(); + }; + + return ( + + {p.rules.map((r, n) => ( + { + deleteRule(n); + }} + onGoDown={ + n < p.rules.length - 1 ? () => swapRules(n, n + 1) : undefined + } + onGoUp={n > 0 ? () => swapRules(n, n - 1) : undefined} + {...p} + /> + ))} + +
+ {p.editable && } +
+
+ ); +} + +function NWRuleEdit(p: { + editable: boolean; + rule: NWFilterRule; + onChange?: () => void; + onGoUp?: () => void; + onGoDown?: () => void; + onDelete: () => void; +}): React.ReactElement { + return ( + + +
+ { + p.rule.action = v as any; + p.onChange?.(); + }} + options={[ + { label: "drop", value: "drop" }, + { label: "reject", value: "reject" }, + { label: "accept", value: "accept" }, + { label: "return", value: "return" }, + { label: "continue", value: "continue" }, + ]} + /> + + { + p.rule.direction = v as any; + p.onChange?.(); + }} + options={[ + { label: "in", value: "in" }, + { label: "out", value: "out" }, + { label: "inout", value: "inout" }, + ]} + /> + + { + p.rule.priority = v && v !== "" ? Number(v) : undefined; + p.onChange?.(); + }} + size={ServerApi.Config.constraints.nwfilter_priority} + /> +
+
+ + {p.editable && ( +
+ + + + + {p.onGoUp && ( + + + + )} + {p.onGoDown && ( + + + + )} +
+ )} +
+
+ ); +} diff --git a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx index 09103f4..531b678 100644 --- a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx +++ b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx @@ -17,6 +17,7 @@ import { TextInput } from "../forms/TextInput"; import { ServerApi } from "../../api/ServerApi"; import { SelectInput } from "../forms/SelectInput"; import { NWFSelectReferencedFilters } from "../forms/NWFSelectReferencedFilters"; +import { NWFilterRules } from "../forms/NWFilterRules"; interface DetailsProps { nwfilter: NWFilter; @@ -159,6 +160,18 @@ function NetworkFilterDetailsTabGeneral( ); } +function NetworkFilterDetailsTabRules( + p: InnerDetailsProps +): React.ReactElement { + return ( + + ); +} + function NetworkFilterDetailsTabXML(p: InnerDetailsProps): React.ReactElement { return (