diff options
| -rw-r--r-- | gui/src/renderer/containers/SelectLocationPage.tsx | 217 |
1 files changed, 131 insertions, 86 deletions
diff --git a/gui/src/renderer/containers/SelectLocationPage.tsx b/gui/src/renderer/containers/SelectLocationPage.tsx index 3ca4ca94ac..1c3f3ff32a 100644 --- a/gui/src/renderer/containers/SelectLocationPage.tsx +++ b/gui/src/renderer/containers/SelectLocationPage.tsx @@ -1,131 +1,176 @@ -import { connect } from 'react-redux'; +import { useCallback, useMemo } from 'react'; import BridgeSettingsBuilder from '../../shared/bridge-settings-builder'; import { LiftedConstraint, Ownership, RelayLocation } from '../../shared/daemon-rpc-types'; import log from '../../shared/logging'; import RelaySettingsBuilder from '../../shared/relay-settings-builder'; import SelectLocation from '../components/SelectLocation'; -import withAppContext, { IAppContext } from '../context'; +import { useAppContext } from '../context'; import { createWireguardRelayUpdater } from '../lib/constraint-updater'; import filterLocations from '../lib/filter-locations'; -import { IHistoryProps, withHistory } from '../lib/history'; +import { useHistory } from '../lib/history'; import { RoutePath } from '../lib/routes'; -import { IReduxState, ReduxDispatch } from '../redux/store'; +import { useSelector } from '../redux/store'; -const mapStateToProps = (state: IReduxState, props: IHistoryProps & IAppContext) => { - let selectedExitLocation: RelayLocation | undefined; - let selectedEntryLocation: RelayLocation | undefined; - let selectedBridgeLocation: LiftedConstraint<RelayLocation> | undefined; - let multihopEnabled = false; +export default function SelectLocationPage() { + const history = useHistory(); - if ('normal' in state.settings.relaySettings) { - const exitLocation = state.settings.relaySettings.normal.location; - if (exitLocation !== 'any') { - selectedExitLocation = exitLocation; - } - } + const { updateRelaySettings, connectTunnel, updateBridgeSettings } = useAppContext(); + + const locale = useSelector((state) => state.userInterface.locale); + const settings = useSelector((state) => state.settings); + const { relaySettings, bridgeSettings, bridgeState } = settings; - const relaySettings = state.settings.relaySettings; - const tunnelProtocol = 'normal' in relaySettings ? relaySettings.normal.tunnelProtocol : 'any'; + const providers = useMemo( + () => ('normal' in relaySettings ? relaySettings.normal.providers : []), + [relaySettings], + ); - if (tunnelProtocol === 'openvpn' && 'normal' in state.settings.bridgeSettings) { - selectedBridgeLocation = state.settings.bridgeSettings.normal.location; - } else if ('normal' in relaySettings) { - multihopEnabled = relaySettings.normal.wireguard.useMultihop; + const ownership = useMemo( + () => ('normal' in relaySettings ? relaySettings.normal.ownership : Ownership.any), + [relaySettings], + ); - const entryLocation = relaySettings.normal.wireguard.entryLocation; - if (multihopEnabled && entryLocation !== 'any') { - selectedEntryLocation = entryLocation; + const tunnelProtocol = useMemo( + () => ('normal' in relaySettings ? relaySettings.normal.tunnelProtocol : 'any'), + [relaySettings], + ); + + const selectedExitLocation = useMemo<RelayLocation | undefined>(() => { + if ('normal' in relaySettings) { + const exitLocation = relaySettings.normal.location; + if (exitLocation !== 'any') { + return exitLocation; + } } - } + return undefined; + }, [relaySettings]); - const allowEntrySelection = - (tunnelProtocol === 'openvpn' && state.settings.bridgeState === 'on') || - ((tunnelProtocol === 'any' || tunnelProtocol === 'wireguard') && multihopEnabled); + const selectedBridgeLocation = useMemo<LiftedConstraint<RelayLocation> | undefined>(() => { + return tunnelProtocol === 'openvpn' && 'normal' in bridgeSettings + ? bridgeSettings.normal.location + : undefined; + }, [tunnelProtocol, bridgeSettings]); - const providers = 'normal' in relaySettings ? relaySettings.normal.providers : []; - const ownership = 'normal' in relaySettings ? relaySettings.normal.ownership : Ownership.any; + const multihopEnabled = useMemo(() => { + return ( + tunnelProtocol !== 'openvpn' && + 'normal' in relaySettings && + relaySettings.normal.wireguard.useMultihop + ); + }, [tunnelProtocol, relaySettings]); - return { - locale: state.userInterface.locale, - selectedExitLocation, - selectedEntryLocation, - selectedBridgeLocation, - relayLocations: filterLocations(state.settings.relayLocations, providers, ownership), - bridgeLocations: filterLocations(state.settings.bridgeLocations, providers, ownership), - allowEntrySelection, - tunnelProtocol, - providers, - ownership, + const selectedEntryLocation = useMemo<RelayLocation | undefined>(() => { + if (multihopEnabled && 'normal' in relaySettings) { + const entryLocation = relaySettings.normal.wireguard.entryLocation; + if (multihopEnabled && entryLocation !== 'any') { + return entryLocation; + } + } + return undefined; + }, [relaySettings, multihopEnabled]); - onSelectEntryLocation: async (entryLocation: RelayLocation) => { - // dismiss the view first - props.history.dismiss(); + const allowEntrySelection = useMemo(() => { + return ( + (tunnelProtocol === 'openvpn' && bridgeState === 'on') || + ((tunnelProtocol === 'any' || tunnelProtocol === 'wireguard') && multihopEnabled) + ); + }, [tunnelProtocol, bridgeState, multihopEnabled]); - const relayUpdate = createWireguardRelayUpdater(state.settings.relaySettings) - .tunnel.wireguard((wireguard) => wireguard.entryLocation.exact(entryLocation)) - .build(); + const relayLocations = filterLocations(settings.relayLocations, providers, ownership); + const bridgeLocations = filterLocations(settings.bridgeLocations, providers, ownership); - try { - await props.app.updateRelaySettings(relayUpdate); - } catch (e) { - const error = e as Error; - log.error('Failed to select the entry location', error.message); - } - }, - }; -}; -const mapDispatchToProps = (_dispatch: ReduxDispatch, props: IHistoryProps & IAppContext) => { - return { - onClose: () => props.history.dismiss(), - onViewFilter: () => props.history.push(RoutePath.filter), - onSelectExitLocation: async (relayLocation: RelayLocation) => { + const onClose = useCallback(() => history.dismiss(), [history]); + const onViewFilter = useCallback(() => history.push(RoutePath.filter), [history]); + const onSelectExitLocation = useCallback( + async (relayLocation: RelayLocation) => { // dismiss the view first - props.history.dismiss(); - + history.dismiss(); try { const relayUpdate = RelaySettingsBuilder.normal().location.fromRaw(relayLocation).build(); - await props.app.updateRelaySettings(relayUpdate); - await props.app.connectTunnel(); + await updateRelaySettings(relayUpdate); + await connectTunnel(); } catch (e) { const error = e as Error; log.error(`Failed to select the exit location: ${error.message}`); } }, - onSelectBridgeLocation: async (bridgeLocation: RelayLocation) => { + [connectTunnel, updateRelaySettings, history], + ); + const onSelectEntryLocation = useCallback( + async (entryLocation: RelayLocation) => { // dismiss the view first - props.history.dismiss(); + history.dismiss(); + + const relayUpdate = createWireguardRelayUpdater(relaySettings) + .tunnel.wireguard((wireguard) => wireguard.entryLocation.exact(entryLocation)) + .build(); try { - await props.app.updateBridgeSettings( - new BridgeSettingsBuilder().location.fromRaw(bridgeLocation).build(), - ); + await updateRelaySettings(relayUpdate); } catch (e) { const error = e as Error; - log.error(`Failed to select the bridge location: ${error.message}`); + log.error('Failed to select the entry location', error.message); } }, - onSelectClosestToExit: async () => { + [history, relaySettings, updateRelaySettings], + ); + const onSelectBridgeLocation = useCallback( + async (bridgeLocation: RelayLocation) => { // dismiss the view first - props.history.dismiss(); + history.dismiss(); try { - await props.app.updateBridgeSettings(new BridgeSettingsBuilder().location.any().build()); + await updateBridgeSettings( + new BridgeSettingsBuilder().location.fromRaw(bridgeLocation).build(), + ); } catch (e) { const error = e as Error; - log.error(`Failed to set the bridge location to closest to exit: ${error.message}`); + log.error(`Failed to select the bridge location: ${error.message}`); } }, - onClearProviders: async () => { - await props.app.updateRelaySettings({ normal: { providers: [] } }); - }, - onClearOwnership: async () => { - await props.app.updateRelaySettings({ normal: { ownership: Ownership.any } }); - }, - }; -}; + [history, updateBridgeSettings], + ); + const onSelectClosestToExit = useCallback(async () => { + history.dismiss(); + + try { + await updateBridgeSettings(new BridgeSettingsBuilder().location.any().build()); + } catch (e) { + const error = e as Error; + log.error(`Failed to set the bridge location to closest to exit: ${error.message}`); + } + }, [updateBridgeSettings, history]); + + const onClearProviders = useCallback(async () => { + await updateRelaySettings({ normal: { providers: [] } }); + }, [updateRelaySettings]); + + const onClearOwnership = useCallback(async () => { + await updateRelaySettings({ normal: { ownership: Ownership.any } }); + }, [updateRelaySettings]); -export default withAppContext( - withHistory(connect(mapStateToProps, mapDispatchToProps)(SelectLocation)), -); + return ( + <SelectLocation + locale={locale} + selectedExitLocation={selectedExitLocation} + selectedEntryLocation={selectedEntryLocation} + selectedBridgeLocation={selectedBridgeLocation} + relayLocations={relayLocations} + bridgeLocations={bridgeLocations} + allowEntrySelection={allowEntrySelection} + tunnelProtocol={tunnelProtocol} + providers={providers} + ownership={ownership} + onClose={onClose} + onViewFilter={onViewFilter} + onSelectExitLocation={onSelectExitLocation} + onSelectEntryLocation={onSelectEntryLocation} + onSelectBridgeLocation={onSelectBridgeLocation} + onSelectClosestToExit={onSelectClosestToExit} + onClearProviders={onClearProviders} + onClearOwnership={onClearOwnership} + /> + ); +} |
