From 7858e4830edf6b5a3a0a331ce9a8982f47cdb43f Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Mon, 22 Jul 2024 09:36:56 +0100 Subject: [PATCH 1/2] Move network to TanStack query --- web/src/client/network/index.js | 23 +- web/src/client/network/model.js | 7 + .../components/network/ConnectionsTable.jsx | 3 +- web/src/components/network/NetworkPage.jsx | 73 +---- .../components/network/WifiConnectionForm.jsx | 13 +- .../network/WifiNetworksListPage.jsx | 35 +-- .../components/network/WifiSelectorPage.jsx | 117 +------- web/src/components/network/routes.js | 36 +-- web/src/queries/network.js | 260 ++++++++++++++++++ 9 files changed, 338 insertions(+), 229 deletions(-) create mode 100644 web/src/queries/network.js diff --git a/web/src/client/network/index.js b/web/src/client/network/index.js index e7a4df7545..103d177482 100644 --- a/web/src/client/network/index.js +++ b/web/src/client/network/index.js @@ -26,6 +26,8 @@ import { ConnectionTypes, createAccessPoint, createConnection, + DeviceState, + NetworkState, securityFromFlags, } from "./model"; import { formatIp, ipPrefixFor } from "./utils"; @@ -239,7 +241,26 @@ class NetworkClient { return this.client.get(`/network/connections/${connection.id}/disconnect`); } - async loadNetworks(devices, connections, accessPoints) { + networkStateFor(state) { + switch (state) { + case DeviceState.CONFIG: + case DeviceState.IPCHECK: + // TRANSLATORS: Wifi network status + return NetworkState.CONNECTING; + case DeviceState.ACTIVATED: + // TRANSLATORS: Wifi network status + return NetworkState.CONNECTED; + case DeviceState.DEACTIVATING: + case DeviceState.FAILED: + case DeviceState.DISCONNECTED: + // TRANSLATORS: Wifi network status + return NetworkState.DISCONNECTED; + default: + return ""; + } + } + + loadNetworks(devices, connections, accessPoints) { const knownSsids = []; return accessPoints diff --git a/web/src/client/network/model.js b/web/src/client/network/model.js index 14aa4b31bd..d28fcc849f 100644 --- a/web/src/client/network/model.js +++ b/web/src/client/network/model.js @@ -49,6 +49,12 @@ const DeviceState = Object.freeze({ FAILED: "failed", }); +const NetworkState = Object.freeze({ + DISCONNECTED: "disconnected", + CONNECTING: "connecting", + CONNECTED: "connected" +}); + /** * Returns a human readable connection state * @@ -302,6 +308,7 @@ export { createConnection, createDevice, DeviceState, + NetworkState, securityFromFlags, SecurityProtocols, }; diff --git a/web/src/components/network/ConnectionsTable.jsx b/web/src/components/network/ConnectionsTable.jsx index e925e3350c..22616074d7 100644 --- a/web/src/components/network/ConnectionsTable.jsx +++ b/web/src/components/network/ConnectionsTable.jsx @@ -64,7 +64,8 @@ export default function ConnectionsTable({ connections, devices, onForget }) { {_("Name")} {/* TRANSLATORS: table header */} {_("IP addresses")} - + {/* TRANSLATORS: table header aria label */} + diff --git a/web/src/components/network/NetworkPage.jsx b/web/src/components/network/NetworkPage.jsx index dc99f2d296..5f926da4d6 100644 --- a/web/src/components/network/NetworkPage.jsx +++ b/web/src/components/network/NetworkPage.jsx @@ -21,58 +21,21 @@ // @ts-check -import React, { useCallback, useEffect, useState } from "react"; -import { CardBody, Grid, GridItem, Skeleton, Split, Stack } from "@patternfly/react-core"; -import { useLoaderData } from "react-router-dom"; +import React from "react"; +import { CardBody, Grid, GridItem } from "@patternfly/react-core"; import { ButtonLink, CardField, EmptyState, Page } from "~/components/core"; import { ConnectionsTable } from "~/components/network"; -import { NetworkEventTypes } from "~/client/network"; -import { useInstallerClient } from "~/context/installer"; import { _ } from "~/i18n"; import { formatIp } from "~/client/network/utils"; import { sprintf } from "sprintf-js"; +import { useNetwork, useNetworkConfigChanges } from "~/queries/network"; /** * Page component holding Network settings * @component */ export default function NetworkPage() { - const { network: client } = useInstallerClient(); - // @ts-ignore - const { connections: initialConnections, devices: initialDevices, settings } = useLoaderData(); - const [connections, setConnections] = useState(initialConnections); - const [devices, setDevices] = useState(initialDevices); - const [updateState, setUpdateState] = useState(false); - - const fetchState = useCallback(async () => { - const devices = await client.devices(); - const connections = await client.connections(); - setDevices(devices); - setConnections(connections); - }, [client]); - - useEffect(() => { - if (!updateState) return; - - setUpdateState(false); - fetchState(); - }, [fetchState, updateState]); - - useEffect(() => { - return client.onNetworkChange(({ type }) => { - if ( - [ - NetworkEventTypes.DEVICE_ADDED, - NetworkEventTypes.DEVICE_UPDATED, - NetworkEventTypes.DEVICE_REMOVED, - // @ts-ignore - ].includes(type) - ) { - setUpdateState(true); - } - }); - }); - + const { connections, devices, settings } = useNetwork(); const connectionDevice = ({ id }) => devices?.find(({ connection }) => id === connection); const connectionAddresses = (connection) => { const device = connectionDevice(connection); @@ -80,8 +43,7 @@ export default function NetworkPage() { return addresses?.map(formatIp).join(", "); }; - - const ready = connections !== undefined && devices !== undefined; + useNetworkConfigChanges(); const WifiConnections = () => { const { wireless_enabled: wifiAvailable } = settings; @@ -132,22 +94,6 @@ export default function NetworkPage() { ); }; - const SectionSkeleton = () => ( - - - - - - - - - - - - - - ); - const WiredConnections = () => { const wiredConnections = connections.filter((c) => !c.wireless); const total = wiredConnections.length; @@ -155,13 +101,8 @@ export default function NetworkPage() { return ( 0 && _("Wired")}> - {!ready && } - {ready && total === 0 && ( - - )} - {ready && total !== 0 && ( - - )} + {total === 0 && ()} + {total !== 0 && ()} ); diff --git a/web/src/components/network/WifiConnectionForm.jsx b/web/src/components/network/WifiConnectionForm.jsx index d4c37e7543..cd745352cf 100644 --- a/web/src/components/network/WifiConnectionForm.jsx +++ b/web/src/components/network/WifiConnectionForm.jsx @@ -19,7 +19,7 @@ * find current contact information at www.suse.com. */ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { ActionGroup, Alert, @@ -32,7 +32,11 @@ import { } from "@patternfly/react-core"; import { PasswordInput } from "~/components/core"; import { useInstallerClient } from "~/context/installer"; +import { useNetwork, useNetworkConfigChanges, useSelectedWifiChange } from "~/queries/network"; import { _ } from "~/i18n"; +import { NetworkEventTypes } from "~/client/network"; +import { DeviceState } from "~/client/network/model"; +import { QueryClient, useQueryClient } from "@tanstack/react-query"; /* * FIXME: it should be moved to the SecurityProtocols enum that already exists or to a class based @@ -57,6 +61,8 @@ const securityFrom = (supported) => { export default function WifiConnectionForm({ network, onCancel, onSubmitCallback }) { const { network: client } = useInstallerClient(); + const queryClient = useQueryClient(); + const { networks } = useNetwork(); const [error, setError] = useState(false); const [isConnecting, setIsConnecting] = useState(false); const [ssid, setSsid] = useState(network?.ssid || ""); @@ -64,6 +70,8 @@ export default function WifiConnectionForm({ network, onCancel, onSubmitCallback const [security, setSecurity] = useState(securityFrom(network?.security || [])); const hidden = network?.hidden || false; + useNetworkConfigChanges(); + const accept = async (e) => { e.preventDefault(); setError(false); @@ -76,7 +84,8 @@ export default function WifiConnectionForm({ network, onCancel, onSubmitCallback client .addAndConnectTo(ssid, { security, password, hidden }) .catch(() => setError(true)) - .finally(() => setIsConnecting(false)); + .finally(() => setIsConnecting(false) && queryClient.invalidateQueries({ "queryKey": ["network"] })); + }; return ( diff --git a/web/src/components/network/WifiNetworksListPage.jsx b/web/src/components/network/WifiNetworksListPage.jsx index b0b21f0f31..d00b4cd2b9 100644 --- a/web/src/components/network/WifiNetworksListPage.jsx +++ b/web/src/components/network/WifiNetworksListPage.jsx @@ -45,12 +45,13 @@ import { } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; import { WifiConnectionForm } from "~/components/network"; -import { ButtonLink, EmptyState } from "~/components/core"; +import { ButtonLink } from "~/components/core"; import { DeviceState } from "~/client/network/model"; import { useInstallerClient } from "~/context/installer"; import { _ } from "~/i18n"; import { formatIp } from "~/client/network/utils"; -import { sprintf } from "sprintf-js"; +import { useQueryClient } from "@tanstack/react-query"; +import { useSelectedWifi, useSelectedWifiChange } from "~/queries/network"; const HIDDEN_NETWORK = Object.freeze({ hidden: true }); @@ -85,11 +86,13 @@ const ConnectionData = ({ network }) => { return {connectionAddresses(network)}; }; -const WifiDrawerPanelBody = ({ network, onCancel, onForget }) => { +const WifiDrawerPanelBody = ({ network, onCancel }) => { const client = useInstallerClient(); + const queryClient = useQueryClient(); + const { data } = useSelectedWifi(); const forgetNetwork = async () => { await client.network.deleteConnection(network.settings.id); - onForget(); + queryClient.invalidateQueries({ queryKey: ["network", "connections"] }) }; if (!network) return; @@ -98,6 +101,8 @@ const WifiDrawerPanelBody = ({ network, onCancel, onForget }) => { if (network === HIDDEN_NETWORK) return
; + if (data.needsAuth) return ; + if (network.settings && !network.device) { return ( @@ -180,22 +185,21 @@ const NetworkListName = ({ network }) => { * @param {function} props.onSelectionCallback - the function to trigger when user selects a network * @param {function} props.onCancelCallback - the function to trigger when user cancel dismiss before connecting to a network */ -function WifiNetworksListPage({ - selected, - onSelectionChange, - networks = [], - forceUpdateNetworksCallback = () => {}, -}) { - const selectHiddenNetwork = () => { - onSelectionChange(HIDDEN_NETWORK); +function WifiNetworksListPage({ networks = [] }) { + const { data } = useSelectedWifi(); + const selected = data.ssid === undefined ? HIDDEN_NETWORK : networks.find(n => n.ssid === data.ssid); + const changeSelected = useSelectedWifiChange(); + + const selectHiddneNetwork = () => { + changeSelected.mutate({ ssid: undefined, needsAuth: null }); }; const selectNetwork = (ssid) => { - onSelectionChange(networks.find((n) => n.ssid === ssid)); + changeSelected.mutate({ ssid, needsAuth: null }); }; const unselectNetwork = () => { - onSelectionChange(undefined); + changeSelected.mutate({ ssid: null, needsAuth: null }); }; const renderElements = () => { @@ -246,7 +250,6 @@ function WifiNetworksListPage({ @@ -261,7 +264,7 @@ function WifiNetworksListPage({ > {renderElements()} - diff --git a/web/src/components/network/WifiSelectorPage.jsx b/web/src/components/network/WifiSelectorPage.jsx index 1f0a82efa0..ed01d6fe5d 100644 --- a/web/src/components/network/WifiSelectorPage.jsx +++ b/web/src/components/network/WifiSelectorPage.jsx @@ -19,116 +19,20 @@ * find current contact information at www.suse.com. */ -import React, { useCallback, useEffect, useState } from "react"; -import { useInstallerClient } from "~/context/installer"; -import { NetworkEventTypes } from "~/client/network"; +import React from "react"; import { Page } from "~/components/core"; import { WifiNetworksListPage } from "~/components/network"; import { _ } from "~/i18n"; -import { DeviceState } from "~/client/network/model"; -import { Grid, GridItem, Timestamp } from "@patternfly/react-core"; -import { useLoaderData } from "react-router-dom"; -import { useLocalStorage } from "~/utils"; +import { Grid, GridItem } from "@patternfly/react-core"; +import { useNetwork, useNetworkConfigChanges } from "~/queries/network"; const networksFromValues = (networks) => Object.values(networks).flat(); -const baseHiddenNetwork = { ssid: undefined, hidden: true }; // FIXME: use a reducer function WifiSelectorPage() { - const { network: client } = useInstallerClient(); - const { - connections: initialConnections, - devices: initialDevices, - accessPoints, - networks: initialNetworks, - } = useLoaderData(); - const [data, saveData] = useLocalStorage("agama-network", { selectedWifi: null }); - // Reevaluate how to keep the state in the future - const [selected, setSelected] = useState(data.selectedWifi); - const [networks, setNetworks] = useState(initialNetworks); - const [showHiddenForm, setShowHiddenForm] = useState(false); - const [devices, setDevices] = useState(initialDevices); - const [connections, setConnections] = useState(initialConnections); - const [activeNetwork, setActiveNetwork] = useState(null); - const [updateNetworks, setUpdateNetworks] = useState(false); - const [needAuth, setNeedAuth] = useState(null); - - const reloadNetworks = () => setUpdateNetworks(true); - - const selectNetwork = (network) => { - saveData({ selectedWifi: network }); - setSelected(network); - }; - - const switchSelectedNetwork = (network) => { - setSelected(network === baseHiddenNetwork); - }; - - const fetchNetworks = useCallback(async () => { - const devices = await client.devices(); - const connections = await client.connections(); - const networks = await client.loadNetworks(devices, connections, accessPoints); - setDevices(devices); - setConnections(connections); - setNetworks(networks); - }, [client, accessPoints]); - - useEffect(() => { - saveData(data); - }, [data, saveData]); - - useEffect(() => { - // Let's keep the selected network up to date after networks information is - // updated (e.g., if the network status change); - if (networks) { - setSelected((prev) => { - return networksFromValues(networks).find((n) => n.ssid === prev?.ssid); - }); - } - }, [networks]); - - useEffect(() => { - setActiveNetwork(networksFromValues(networks).find((d) => d.device)); - }, [networks]); - - useEffect(() => { - if (!updateNetworks) return; - - setUpdateNetworks(false); - fetchNetworks(); - }, [fetchNetworks, updateNetworks]); - - useEffect(() => { - return client.onNetworkChange(({ type, payload }) => { - switch (type) { - case NetworkEventTypes.DEVICE_ADDED: { - reloadNetworks(); - break; - } - - case NetworkEventTypes.DEVICE_UPDATED: { - const [name, data] = payload; - const current_device = devices.find((d) => d.name === name); - - if (data.state === DeviceState.FAILED) { - if (current_device && data.stateReason === 7) { - console.log(`FAILED Device ${name} updated' with data`, data); - setNeedAuth(current_device.connection); - } - } - - reloadNetworks(); - break; - } - - case NetworkEventTypes.DEVICE_REMOVED: { - reloadNetworks(); - break; - } - } - }); - }); + const { networks } = useNetwork(); + useNetworkConfigChanges(); return ( <> @@ -138,16 +42,7 @@ function WifiSelectorPage() { - + diff --git a/web/src/components/network/routes.js b/web/src/components/network/routes.js index 2627c6381f..48a8947469 100644 --- a/web/src/components/network/routes.js +++ b/web/src/components/network/routes.js @@ -23,35 +23,9 @@ import React from "react"; import { Page } from "~/components/core"; import NetworkPage from "./NetworkPage"; import IpSettingsForm from "./IpSettingsForm"; -import { createDefaultClient } from "~/client"; import WifiSelectorPage from "./WifiSelectorPage"; import { N_ } from "~/i18n"; -// FIXME: just to be discussed, most probably we should reading data directly in -// the component in order to get it subscribed to changes. -const client = await createDefaultClient(); - -const loaders = { - all: async () => { - const devices = await client.network.devices(); - const connections = await client.network.connections(); - const settings = await client.network.settings(); - return { connections, devices, settings }; - }, - connection: async ({ params }) => { - const connections = await client.network.connections(); - return connections.find((c) => c.id === params.id); - }, - wifis: async () => { - const connections = await client.network.connections(); - const devices = await client.network.devices(); - const accessPoints = await client.network.accessPoints(); - const networks = await client.network.loadNetworks(devices, connections, accessPoints); - - return { connections, devices, accessPoints, networks }; - }, -}; - const routes = { path: "/network", element: , @@ -60,18 +34,16 @@ const routes = { icon: "settings_ethernet", }, children: [ - { index: true, element: , loader: loaders.all }, + { index: true, element: }, { path: "connections/:id/edit", - element: , - loader: loaders.connection, + element: }, { path: "wifis", element: , - loader: loaders.wifis, - }, - ], + } + ] }; export default routes; diff --git a/web/src/queries/network.js b/web/src/queries/network.js new file mode 100644 index 0000000000..f476b72a89 --- /dev/null +++ b/web/src/queries/network.js @@ -0,0 +1,260 @@ +/* + * Copyright (c) [2024] SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact SUSE LLC. + * + * To contact SUSE LLC about this file by physical or electronic mail, you may + * find current contact information at www.suse.com. + */ + +import React from "react"; +import { useQueryClient, useMutation, useSuspenseQuery, useSuspenseQueries } from "@tanstack/react-query"; +import { useInstallerClient } from "~/context/installer"; +import { DeviceState, createAccessPoint, securityFromFlags } from "~/client/network/model"; +import { ipPrefixFor } from "~/client/network/utils"; +/** + * Returns the device settings + * + * @param {object} device - device settings from the API server + * @return {Device} + */ +const fromApiDevice = (device) => { + const nameservers = (device?.ipConfig?.nameservers || []); + const { ipConfig = {}, ...dev } = device; + const routes4 = (ipConfig.routes4 || []).map((route) => { + const [ip, netmask] = route.destination.split("/"); + const destination = (netmask !== undefined) ? { address: ip, prefix: ipPrefixFor(netmask) } : { address: ip }; + + return { ...route, destination }; + }); + + const routes6 = (ipConfig.routes6 || []).map((route) => { + const [ip, netmask] = route.destination.split("/"); + const destination = (netmask !== undefined) ? { address: ip, prefix: ipPrefixFor(netmask) } : { address: ip }; + + return { ...route, destination }; + }); + + const addresses = (ipConfig.addresses || []).map((address) => { + const [ip, netmask] = address.split("/"); + if (netmask !== undefined) { + return { address: ip, prefix: ipPrefixFor(netmask) }; + } else { + return { address: ip }; + } + }); + + return { ...dev, ...ipConfig, addresses, nameservers, routes4, routes6 }; +}; + +const fromApiConnection = (connection) => { + const nameservers = (connection.nameservers || []); + const addresses = (connection.addresses || []).map((address) => { + const [ip, netmask] = address.split("/"); + if (netmask !== undefined) { + return { address: ip, prefix: ipPrefixFor(netmask) }; + } else { + return { address: ip }; + } + }); + + return { ...connection, addresses, nameservers }; +}; + +/** + * Returns a query for retrieving the network configuration + */ +const stateQuery = () => { + return { + queryKey: ["network", "state"], + queryFn: () => fetch("/api/network/state").then((res) => res.json()), + }; +}; + +/** + * Returns a query for retrieving the list of known devices + */ +const devicesQuery = () => ({ + queryKey: ["network", "devices"], + queryFn: async () => { + const response = await fetch("/api/network/devices"); + const devices = await response.json(); + + return devices.map(fromApiDevice); + }, + staleTime: Infinity +}); + +/** + * Returns a query for retrieving the list of known connections + */ +const connectionsQuery = () => ({ + queryKey: ["network", "connections"], + queryFn: async () => { + const response = await fetch("/api/network/connections"); + const connections = await response.json(); + return connections.map(fromApiConnection); + }, + staleTime: Infinity +}); + +/** + * Returns a query for retrieving the list of known access points + */ +const accessPointsQuery = () => ({ + queryKey: ["network", "accessPoints"], + queryFn: async () => { + const response = await fetch("/api/network/wifi"); + const json = await response.json(); + const access_points = json.map((ap) => { + return createAccessPoint({ + ssid: ap.ssid, + hwAddress: ap.hw_address, + strength: ap.strength, + security: securityFromFlags(ap.flags, ap.wpaFlags, ap.rsnFlags) + }); + }); + return access_points.sort((a, b) => (a.strength < b.strength) ? -1 : 1); + }, + staleTime: Infinity +}); + +/** + * Hook that builds a mutation to update a network connections + * + * It does not require to call `useMutation`. + */ +const useConnectionMutation = () => { + const query = { + mutationFn: (newConnection) => + fetch(`/api/network/connection/${newConnection.id}`, { + method: "PUT", + body: JSON.stringify(newConnection), + headers: { + "Content-Type": "application/json", + }, + }) + }; + return useMutation(query); +}; + +/** + * Returns selected Wi-Fi network + */ +const selectedWiFiNetworkQuery = () => ({ + // queryKey: ["network", "wifi", "selected"], + // TODO: use right key, once we stop invalidating everything under network + queryKey: ["wifi", "selected"], + queryFn: async () => { + return Promise.resolve({ ssid: null, needsAuth: null }); + }, + staleTime: Infinity +}); + +const useSelectedWifi = () => { + // TODO: evaluate if useSuspenseQuery is really needed, probably not. + return useSuspenseQuery(selectedWiFiNetworkQuery()); +} + +const useSelectedWifiChange = () => { + const queryClient = useQueryClient(); + + const mutation = useMutation({ + mutationFn: async (data) => Promise.resolve(data), + onSuccess: (data) => { + queryClient.setQueryData(["wifi", "selected"], (prev) => ({ ...prev, ...data })); + } + }); + + return mutation; +} + +/** + * Hook that returns a useEffect to listen for NetworkChanged events + * + * When the configuration changes, it invalidates the config query and forces the router to + * revalidate its data (executing the loaders again). + */ +const useNetworkConfigChanges = () => { + const queryClient = useQueryClient(); + const client = useInstallerClient(); + const changeSelected = useSelectedWifiChange(); + + React.useEffect(() => { + if (!client) return; + + return client.ws().onEvent((event) => { + if (event.type === "NetworkChange") { + if (event.deviceRemoved || event.deviceAdded) { + queryClient.invalidateQueries({ queryKey: ["network"] }); + } + + if (event.deviceUpdated) { + const [name, data] = event.deviceUpdated; + const devices = queryClient.getQueryData(["network", "devices"]); + if (!devices) return; + + if (name !== data.name) { + return queryClient.invalidateQueries({ queryKey: ["network"] }); + } + + const current_device = devices.find((d) => d.name === name); + if ([DeviceState.DISCONNECTED, DeviceState.ACTIVATED].includes(data.state)) { + if (current_device.state !== data.state) { + return queryClient.invalidateQueries({ queryKey: ["network"] }); + } + } + if (data.state === DeviceState.FAILED) { + return changeSelected.mutate({ needsAuth: true }); + } + } + } + }); + }, [client, queryClient, changeSelected]); +}; + +const useNetwork = () => { + const [ + { data: state }, + { data: devices }, + { data: connections }, + { data: accessPoints } + ] = useSuspenseQueries({ + queries: [ + stateQuery(), + devicesQuery(), + connectionsQuery(), + accessPointsQuery() + ] + }); + const client = useInstallerClient(); + const networks = client.network.loadNetworks(devices, connections, accessPoints); + + return { connections, settings: state, devices, accessPoints, networks }; +}; + + +export { + stateQuery, + devicesQuery, + connectionsQuery, + accessPointsQuery, + selectedWiFiNetworkQuery, + useConnectionMutation, + useNetwork, + useSelectedWifi, + useSelectedWifiChange, + useNetworkConfigChanges +}; From c82cc1e8ff4dc14ada13663e63699da9a8442c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 23 Jul 2024 08:43:11 +0100 Subject: [PATCH 2/2] fix(web) make failing tests works again --- web/src/components/network/WifiConnectionForm.jsx | 12 +++++------- .../components/network/WifiConnectionForm.test.jsx | 4 ++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/web/src/components/network/WifiConnectionForm.jsx b/web/src/components/network/WifiConnectionForm.jsx index cd745352cf..275a083303 100644 --- a/web/src/components/network/WifiConnectionForm.jsx +++ b/web/src/components/network/WifiConnectionForm.jsx @@ -32,11 +32,9 @@ import { } from "@patternfly/react-core"; import { PasswordInput } from "~/components/core"; import { useInstallerClient } from "~/context/installer"; -import { useNetwork, useNetworkConfigChanges, useSelectedWifiChange } from "~/queries/network"; +import { useNetworkConfigChanges } from "~/queries/network"; import { _ } from "~/i18n"; -import { NetworkEventTypes } from "~/client/network"; -import { DeviceState } from "~/client/network/model"; -import { QueryClient, useQueryClient } from "@tanstack/react-query"; +import { useQueryClient } from "@tanstack/react-query"; /* * FIXME: it should be moved to the SecurityProtocols enum that already exists or to a class based @@ -62,7 +60,6 @@ const securityFrom = (supported) => { export default function WifiConnectionForm({ network, onCancel, onSubmitCallback }) { const { network: client } = useInstallerClient(); const queryClient = useQueryClient(); - const { networks } = useNetwork(); const [error, setError] = useState(false); const [isConnecting, setIsConnecting] = useState(false); const [ssid, setSsid] = useState(network?.ssid || ""); @@ -84,8 +81,9 @@ export default function WifiConnectionForm({ network, onCancel, onSubmitCallback client .addAndConnectTo(ssid, { security, password, hidden }) .catch(() => setError(true)) - .finally(() => setIsConnecting(false) && queryClient.invalidateQueries({ "queryKey": ["network"] })); - + .finally( + () => setIsConnecting(false) && queryClient.invalidateQueries({ queryKey: ["network"] }), + ); }; return ( diff --git a/web/src/components/network/WifiConnectionForm.test.jsx b/web/src/components/network/WifiConnectionForm.test.jsx index b332ec1069..b500af8e10 100644 --- a/web/src/components/network/WifiConnectionForm.test.jsx +++ b/web/src/components/network/WifiConnectionForm.test.jsx @@ -28,6 +28,10 @@ import { WifiConnectionForm } from "~/components/network"; jest.mock("~/client"); +jest.mock("~/queries/network", () => ({ + useNetworkConfigChanges: jest.fn(), +})); + Element.prototype.scrollIntoView = jest.fn(); const hiddenNetworkMock = {