Skip to content

Commit

Permalink
fix(network) avoid crash when manually trying to access network confi…
Browse files Browse the repository at this point in the history
…g for non-managed networks, show notification instead, fixes #757

Signed-off-by: David Edler <[email protected]>
  • Loading branch information
edlerd committed Apr 30, 2024
1 parent c9d3cc6 commit 1647a00
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 123 deletions.
16 changes: 15 additions & 1 deletion src/pages/networks/EditNetwork.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { FC, useState } from "react";
import { ActionButton, Button, useNotify } from "@canonical/react-components";
import {
ActionButton,
Button,
Notification,
useNotify,
} from "@canonical/react-components";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useQueryClient } from "@tanstack/react-query";
Expand Down Expand Up @@ -34,6 +39,15 @@ const EditNetwork: FC<Props> = ({ network, project }) => {
const queryClient = useQueryClient();
const controllerState = useState<AbortController | null>(null);

if (!network?.managed) {
return (
<Notification severity="negative">
Configuration is only available for managed networks. This network is
not managed.
</Notification>
);
}

const NetworkSchema = Yup.object().shape({
name: Yup.string()
.test(
Expand Down
17 changes: 14 additions & 3 deletions src/pages/networks/NetworkDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import CustomLayout from "components/CustomLayout";
import TabLinks from "components/TabLinks";
import NetworkForwards from "pages/networks/NetworkForwards";

const tabs: string[] = ["Overview", "Configuration", "Forwards"];

const NetworkDetail: FC = () => {
const { name, project, activeTab } = useParams<{
name: string;
Expand All @@ -39,6 +37,19 @@ const NetworkDetail: FC = () => {
return <Loader />;
}

const getTabs = () => {
if (!network?.managed) {
return ["Overview"];
}

const type = network?.type ?? "";
if (type === "physical") {
return ["Overview", "Configuration"];
}

return ["Overview", "Configuration", "Forwards"];
};

return (
<CustomLayout
header={
Expand All @@ -48,7 +59,7 @@ const NetworkDetail: FC = () => {
>
<Row>
<TabLinks
tabs={network?.managed ? tabs : ["Overview"]}
tabs={getTabs()}
activeTab={activeTab}
tabUrl={`/ui/project/${project}/network/${name}`}
/>
Expand Down
162 changes: 82 additions & 80 deletions src/pages/networks/forms/NetworkFormMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,91 +61,93 @@ const NetworkFormMain: FC<Props> = ({ formik, project }) => {
)}
</Col>
</Row>
<ConfigurationTable
rows={[
getConfigurationRow({
formik,
name: "ipv4_address",
label: "IPv4 address",
defaultValue: "auto",
children: (
<IpAddressSelector
id="ipv4_address"
address={formik.values.ipv4_address}
setAddress={(value) => {
void formik.setFieldValue("ipv4_address", value);
{formik.values.networkType !== "physical" && (
<ConfigurationTable
rows={[
getConfigurationRow({
formik,
name: "ipv4_address",
label: "IPv4 address",
defaultValue: "auto",
children: (
<IpAddressSelector
id="ipv4_address"
address={formik.values.ipv4_address}
setAddress={(value) => {
void formik.setFieldValue("ipv4_address", value);

if (value === "none") {
const nullFields = [
"ipv4_nat",
"ipv4_dhcp",
"ipv4_dhcp_expiry",
"ipv4_dhcp_ranges",
];
nullFields.forEach(
(field) => void formik.setFieldValue(field, undefined),
);
}
}}
/>
),
}),
if (value === "none") {
const nullFields = [
"ipv4_nat",
"ipv4_dhcp",
"ipv4_dhcp_expiry",
"ipv4_dhcp_ranges",
];
nullFields.forEach(
(field) => void formik.setFieldValue(field, undefined),
);
}
}}
/>
),
}),

...(formik.values.ipv4_address !== "none"
? [
getConfigurationRow({
formik,
name: "ipv4_nat",
label: "IPv4 NAT",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),
...(formik.values.ipv4_address !== "none"
? [
getConfigurationRow({
formik,
name: "ipv4_nat",
label: "IPv4 NAT",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),

getConfigurationRow({
formik,
name: "ipv6_address",
label: "IPv6 address",
defaultValue: "auto",
children: (
<IpAddressSelector
id="ipv6_address"
address={formik.values.ipv6_address}
setAddress={(value) => {
void formik.setFieldValue("ipv6_address", value);
getConfigurationRow({
formik,
name: "ipv6_address",
label: "IPv6 address",
defaultValue: "auto",
children: (
<IpAddressSelector
id="ipv6_address"
address={formik.values.ipv6_address}
setAddress={(value) => {
void formik.setFieldValue("ipv6_address", value);

if (value === "none") {
const nullFields = [
"ipv6_nat",
"ipv6_dhcp",
"ipv6_dhcp_expiry",
"ipv6_dhcp_ranges",
"ipv6_dhcp_stateful",
"ipv6_ovn_ranges",
];
nullFields.forEach(
(field) => void formik.setFieldValue(field, undefined),
);
}
}}
/>
),
}),
if (value === "none") {
const nullFields = [
"ipv6_nat",
"ipv6_dhcp",
"ipv6_dhcp_expiry",
"ipv6_dhcp_ranges",
"ipv6_dhcp_stateful",
"ipv6_ovn_ranges",
];
nullFields.forEach(
(field) => void formik.setFieldValue(field, undefined),
);
}
}}
/>
),
}),

...(formik.values.ipv6_address !== "none"
? [
getConfigurationRow({
formik,
name: "ipv6_nat",
label: "IPv6 NAT",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),
]}
/>
...(formik.values.ipv6_address !== "none"
? [
getConfigurationRow({
formik,
name: "ipv6_nat",
label: "IPv6 NAT",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),
]}
/>
)}
</ScrollableForm>
);
};
Expand Down
76 changes: 39 additions & 37 deletions src/pages/networks/forms/NetworkFormMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,51 +42,53 @@ const NetworkFormMenu: FC<Props> = ({ active, setActive, formik }) => {
<nav aria-label="Network form navigation">
<ul className="p-side-navigation__list">
<MenuItem label={MAIN_CONFIGURATION} {...menuItemProps} />
<li className="p-side-navigation__item">
<Button
type="button"
className="p-side-navigation__accordion-button"
aria-expanded={
!disableReason && isAdvancedOpen ? "true" : "false"
}
onClick={() => setAdvancedOpen(!isAdvancedOpen)}
disabled={Boolean(disableReason)}
title={disableReason}
>
Advanced
</Button>
<ul
className="p-side-navigation__list"
aria-expanded={
!disableReason && isAdvancedOpen ? "true" : "false"
}
>
<MenuItem
label={BRIDGE}
{...menuItemProps}
disableReason={disableReason}
/>
<MenuItem
label={DNS}
{...menuItemProps}
disableReason={disableReason}
/>
{formik.values.ipv4_address !== "none" && (
{formik.values.networkType !== "physical" && (
<li className="p-side-navigation__item">
<Button
type="button"
className="p-side-navigation__accordion-button"
aria-expanded={
!disableReason && isAdvancedOpen ? "true" : "false"
}
onClick={() => setAdvancedOpen(!isAdvancedOpen)}
disabled={Boolean(disableReason)}
title={disableReason}
>
Advanced
</Button>
<ul
className="p-side-navigation__list"
aria-expanded={
!disableReason && isAdvancedOpen ? "true" : "false"
}
>
<MenuItem
label={IPV4}
label={BRIDGE}
{...menuItemProps}
disableReason={disableReason}
/>
)}
{formik.values.ipv6_address !== "none" && (
<MenuItem
label={IPV6}
label={DNS}
{...menuItemProps}
disableReason={disableReason}
/>
)}
</ul>
</li>
{formik.values.ipv4_address !== "none" && (
<MenuItem
label={IPV4}
{...menuItemProps}
disableReason={disableReason}
/>
)}
{formik.values.ipv6_address !== "none" && (
<MenuItem
label={IPV6}
{...menuItemProps}
disableReason={disableReason}
/>
)}
</ul>
</li>
)}
<MenuItem
label={YAML_CONFIGURATION}
{...menuItemProps}
Expand Down
10 changes: 9 additions & 1 deletion src/pages/networks/forms/NetworkTypeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ const NetworkTypeSelector: FC<Props> = ({ formik }) => {
value: "ovn",
disabled: !hasOvn,
},
...(formik.values.networkType === "physical"
? [
{
label: "Physical",
value: "physical",
},
]
: []),
]}
onChange={(e) => {
if (e.target.value === "bridge") {
Expand All @@ -71,7 +79,7 @@ const NetworkTypeSelector: FC<Props> = ({ formik }) => {
}
}}
value={formik.values.networkType}
disabled={formik.values.readOnly}
disabled={formik.values.readOnly || !formik.values.isCreating}
/>
);
};
Expand Down
3 changes: 3 additions & 0 deletions src/types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export interface LxdConfigOptions {
cluster: LxcConfigOptionCategories;
instance: LxcConfigOptionCategories;
"network-bridge": LxcConfigOptionCategories;
"network-macvlan": LxcConfigOptionCategories;
"network-ovn": LxcConfigOptionCategories;
"network-physical": LxcConfigOptionCategories;
"network-sriov": LxcConfigOptionCategories;
project: LxcConfigOptionCategories;
server: LxcConfigOptionCategories;
"storage-btrfs": LxcConfigOptionCategories;
Expand Down
7 changes: 6 additions & 1 deletion src/types/network.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export type LxdNetworkBridgeDriver = "native" | "openvswitch";
export type LxdNetworkType = "bridge" | "ovn";
export type LxdNetworkType =
| "bridge"
| "ovn"
| "physical"
| "macvlan"
| "sriov";
export type LxdNetworkDnsMode = "none" | "managed" | "dynamic";
export type LxdNetworkFanType = "vxlan" | "ipip";

Expand Down
3 changes: 3 additions & 0 deletions src/util/networks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ export const getNetworkKey = (formField: string): keyof LxdNetworkConfig => {
const networkTypeToOptionKey: Record<string, LxdConfigOptionsKeys> = {
bridge: "network-bridge",
ovn: "network-ovn",
macvlan: "network-macvlan",
physical: "network-physical",
sriov: "network-sriov",
};

export const networkFormTypeToOptionKey = (
Expand Down

0 comments on commit 1647a00

Please sign in to comment.