Skip to content

Commit

Permalink
Resolve the state refresh between table view and table edit
Browse files Browse the repository at this point in the history
Signed-off-by: Brent Salisbury <[email protected]>
  • Loading branch information
nerdalert committed Oct 1, 2023
1 parent 6370500 commit 7705762
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 148 deletions.
167 changes: 90 additions & 77 deletions ui/src/pages/SecurityGroups/SecurityGroupEditRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const EditRules: React.FC<EditRulesProps> = ({
"success" | "error" | "info" | null
>(null);

const [ipRangeInputValue, setIpRangeInputValue] = useState<string>("");
const [ipRangeInputValue, setIpRangeInputValue] = useState<string[]>([]);

useEffect(() => {
// Initialize tempPortValues whenever secRule changes
Expand Down Expand Up @@ -275,13 +275,19 @@ const EditRules: React.FC<EditRulesProps> = ({
<div style={{ marginTop: "20px", marginBottom: "10px" }}>
<ButtonGroup variant="outlined" style={{ marginRight: "10px" }}>
<Button onClick={handleAddRule}>Add Rule</Button>
<Tooltip title="Adding a rule will begin blocking all traffic not explicitly allowed by a rule for the traffic direction you are editing (inbound or outbound)">
<Tooltip
title="Adding a rule will begin blocking all traffic not explicitly allowed by a rule for the traffic direction you are editing (inbound or outbound)"
placement="top"
>
<Button onClick={() => {}}>
<HelpOutlineIcon />
</Button>
</Tooltip>
<Button onClick={handleSaveRules}>Save Rules</Button>
<Tooltip title="Removing all rules will allow all traffic for the rule direction you are editing (inbound or outbound)">
<Tooltip
title="Removing all rules will allow all traffic for the rule direction you are editing (inbound or outbound)"
placement="top"
>
<Button onClick={() => {}}>
<HelpOutlineIcon />
</Button>
Expand All @@ -298,7 +304,7 @@ const EditRules: React.FC<EditRulesProps> = ({
<div style={{ display: "flex", alignItems: "center" }}>
Port Range
<Tooltip
title="Add a single port number or a comma-seperated number range"
title="Add a port number or a comma-seperated port range."
placement="top"
>
<HelpOutlineIcon
Expand All @@ -308,7 +314,7 @@ const EditRules: React.FC<EditRulesProps> = ({
</Tooltip>
</div>
</TableCell>
<TableCell style={{ fontSize: "14", width: "25%" }}>
<TableCell style={{ fontSize: "14", width: "40%" }}>
<div style={{ display: "flex", alignItems: "center" }}>
IP Ranges
<Tooltip
Expand Down Expand Up @@ -426,80 +432,87 @@ const EditRules: React.FC<EditRulesProps> = ({
paddingBottom: hasErrorInRow(index) ? "2em" : undefined,
}}
>
<Tooltip
title="Add a an IP range in the form of an IP address, an IP CIDR or a comma seperated address range and then hit return to populate the list"
placement="top"
>
<Autocomplete
multiple // allow multiple prefixes in the cell
inputValue={ipRangeInputValue}
onInputChange={(_, newInputValue) => {
console.debug(
"onInputChange - newInputValue:",
newInputValue,
);
setIpRangeInputValue(newInputValue);
}}
disabled={isUnmodifiableIpRange(rule.ip_protocol)}
options={[
"::/0",
"0.0.0.0/0",
{
title: "Organization IPv4",
value: "100.64.0.0/10",
},
{ title: "Organization IPv6", value: "0200::/8" },
]}
getOptionLabel={(option) =>
typeof option === "string" ? option : option.title
}
getOptionDisabled={(option) =>
isUnmodifiableIpRange(rule.ip_protocol)
}
value={rule.ip_ranges || []}
freeSolo
autoHighlight // Highlight the first match as the user types
onChange={(_, newValue) => {
console.debug("onChange - newValue:", newValue);
// If the protocol is unmodifiable, clear the IP ranges for this rule
if (isUnmodifiableIpRange(rule.ip_protocol)) {
const updatedRule = { ...rule, ip_ranges: [] };
onRuleChange(index, updatedRule);
setIpRangeInputValue("");
return;
}
// Otherwise, update the IP ranges as normal
const updatedIpRanges = newValue.map((item) =>
typeof item === "string" || typeof item === "number"
? item
: item.value,
);
const updatedRule = {
...rule,
ip_ranges: updatedIpRanges,
};
<Autocomplete
multiple // allow multiple prefixes in the cell
inputValue={ipRangeInputValue[index] || ""} // Use index to manage individual rows
onInputChange={(_, newInputValue) => {
console.debug(
"onInputChange - newInputValue:",
newInputValue,
);
// Update state for the individual row
setIpRangeInputValue((prev) => {
const newArr = [...prev];
newArr[index] = newInputValue;
return newArr;
});
}}
disabled={isUnmodifiableIpRange(rule.ip_protocol)}
options={[
"::/0",
"0.0.0.0/0",
{
title: "Organization IPv4",
value: "100.64.0.0/10",
},
{ title: "Organization IPv6", value: "0200::/8" },
]}
getOptionLabel={(option) =>
typeof option === "string" ? option : option.title
}
getOptionDisabled={(option) =>
isUnmodifiableIpRange(rule.ip_protocol)
}
value={rule.ip_ranges || []}
freeSolo
autoHighlight // Highlight the first match as the user types
onChange={(_, newValue) => {
console.debug("onChange - newValue:", newValue);
if (isUnmodifiableIpRange(rule.ip_protocol)) {
const updatedRule = { ...rule, ip_ranges: [] };
onRuleChange(index, updatedRule);
setIpRangeInputValue(""); // Clear the input value
}}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
size="small"
fullWidth
style={{
backgroundColor: isUnmodifiableIpRange(
rule.ip_protocol,
)
? "#E8F4F9"
: "transparent",
}}
disabled={isUnmodifiableIpRange(rule.ip_protocol)}
/>
)}
/>
</Tooltip>
setIpRangeInputValue((prev) => {
const newArr = [...prev];
newArr[index] = "";
return newArr;
});
return;
}
const updatedIpRanges = newValue.map((item) =>
typeof item === "string" || typeof item === "number"
? item
: item.value,
);
const updatedRule = {
...rule,
ip_ranges: updatedIpRanges,
};
onRuleChange(index, updatedRule);
setIpRangeInputValue((prev) => {
const newArr = [...prev];
newArr[index] = "";
return newArr;
}); // Clear the input value
}}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
size="small"
fullWidth
style={{
backgroundColor: isUnmodifiableIpRange(
rule.ip_protocol,
)
? "#E8F4F9"
: "transparent",
}}
disabled={isUnmodifiableIpRange(rule.ip_protocol)}
/>
)}
/>
</TableCell>

{/*Actions Column*/}
<TableCell
style={{
Expand Down
4 changes: 2 additions & 2 deletions ui/src/pages/SecurityGroups/SecurityGroupStructs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ interface UpdateSecurityGroup {
outbound_rules: SecurityRule[];
}

type Organization = {
interface Organization {
id: string;
name: string;
security_group_id: string;
};
}

export type {
SecurityGroup,
Expand Down
23 changes: 14 additions & 9 deletions ui/src/pages/SecurityGroups/SecurityGroupTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ interface Props {
data: SecurityGroup;
type: "inbound_rules" | "outbound_rules";
editable?: boolean;
// callback to parent to update rules
updateData?: (
type: "inbound_rules" | "outbound_rules",
updatedRules: SecurityRule[],
) => void;
inboundRules: SecurityRule[];
outboundRules: SecurityRule[];
}

const SecurityGroupTable: React.FC<Props> = ({
data,
type,
editable = false,
updateData,
}) => {
const derivedRules =
const derivedRules: SecurityRule[] =
type === "inbound_rules"
? data.inbound_rules || []
: data.outbound_rules || [];
Expand All @@ -39,17 +39,22 @@ const SecurityGroupTable: React.FC<Props> = ({

useEffect(() => {
console.log("Setting rules in useEffect:", derivedRules);
if (!rules.length) {
// Only update if the rules are empty (TODO: not sure this is needed)
setRules(derivedRules);
}
// Force update the rules from derivedRules
setRules(derivedRules);
}, [type, data]);

const handleDeleteRule = (index: number) => {
const handleDeleteRule = (index: number): void => {
const newRules = [...rules];
newRules.splice(index, 1);
setRules(newRules);
updateData && updateData(type, newRules);

if (updateData) {
updateData(type, newRules);
} else {
console.warn(
"updateData function is not provided, changes won't propagate.",
);
}
};

const handleRuleChange = (
Expand Down
Loading

0 comments on commit 7705762

Please sign in to comment.