summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/lib
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-11-17 17:57:35 +0100
committerOskar Nyberg <oskar@mullvad.net>2022-11-24 16:26:28 +0100
commit4f8f400dd010235a3e52fc9294bebad06166f27e (patch)
tree33d95e84efe30945b14fdb4ecf5939f3a2ccca3d /gui/src/renderer/lib
parent83e0a8758668a803b3865d926579bb79d7df1415 (diff)
downloadmullvadvpn-4f8f400dd010235a3e52fc9294bebad06166f27e.tar.xz
mullvadvpn-4f8f400dd010235a3e52fc9294bebad06166f27e.zip
Add search field to select location view
Diffstat (limited to 'gui/src/renderer/lib')
-rw-r--r--gui/src/renderer/lib/filter-locations.ts50
-rw-r--r--gui/src/renderer/lib/utilityHooks.ts25
2 files changed, 53 insertions, 22 deletions
diff --git a/gui/src/renderer/lib/filter-locations.ts b/gui/src/renderer/lib/filter-locations.ts
index c1ea17106f..5352df41bd 100644
--- a/gui/src/renderer/lib/filter-locations.ts
+++ b/gui/src/renderer/lib/filter-locations.ts
@@ -12,25 +12,30 @@ export enum EndpointType {
exit,
}
-export function filterLocations(
+export function filterLocationsByEndPointType(
locations: IRelayLocationRedux[],
endpointType: EndpointType,
relaySettings?: NormalRelaySettingsRedux,
+): IRelayLocationRedux[] {
+ return filterLocationsImpl(locations, getTunnelProtocolFilter(endpointType, relaySettings));
+}
+
+export function filterLocations(
+ locations: IRelayLocationRedux[],
ownership?: Ownership,
providers?: Array<string>,
): IRelayLocationRedux[] {
- const byTunnelProtocol = filterByTunnelProtocol(locations, endpointType, relaySettings);
- const byOwnership = filterByOwnership(byTunnelProtocol, ownership ?? relaySettings?.ownership);
- const byProvider = filterByProvider(byOwnership, providers ?? relaySettings?.providers);
+ const filters = [getOwnershipFilter(ownership), getProviderFilter(providers)];
- return byProvider;
+ return filters.some((filter) => filter !== undefined)
+ ? filterLocationsImpl(locations, (relay) => filters.every((filter) => filter?.(relay) ?? true))
+ : locations;
}
-function filterByTunnelProtocol(
- locations: IRelayLocationRedux[],
+function getTunnelProtocolFilter(
endpointType: EndpointType,
relaySettings?: NormalRelaySettingsRedux,
-) {
+): (relay: IRelayLocationRelayRedux) => boolean {
const tunnelProtocol = relaySettings?.tunnelProtocol ?? 'any';
const endpointTypes: Array<RelayEndpointType> = [];
if (endpointType !== EndpointType.exit && tunnelProtocol === 'openvpn') {
@@ -44,28 +49,26 @@ function filterByTunnelProtocol(
endpointTypes.push(tunnelProtocol);
}
- return filterLocationsImpl(locations, (relay) => endpointTypes.includes(relay.endpointType));
+ return (relay) => endpointTypes.includes(relay.endpointType);
}
-function filterByOwnership(
- locations: IRelayLocationRedux[],
+function getOwnershipFilter(
ownership?: Ownership,
-): IRelayLocationRedux[] {
+): ((relay: IRelayLocationRelayRedux) => boolean) | undefined {
if (ownership === undefined || ownership === Ownership.any) {
- return locations;
+ return undefined;
}
const expectOwned = ownership === Ownership.mullvadOwned;
- return filterLocationsImpl(locations, (relay) => relay.owned === expectOwned);
+ return (relay) => relay.owned === expectOwned;
}
-function filterByProvider(
- locations: IRelayLocationRedux[],
+function getProviderFilter(
providers?: string[],
-): IRelayLocationRedux[] {
+): ((relay: IRelayLocationRelayRedux) => boolean) | undefined {
return providers === undefined || providers.length === 0
- ? locations
- : filterLocationsImpl(locations, (relay) => providers.includes(relay.provider));
+ ? undefined
+ : (relay) => providers.includes(relay.provider);
}
function filterLocationsImpl(
@@ -89,7 +92,7 @@ export function searchForLocations(
return countries.reduce((countries, country) => {
const matchingCities = searchCities(country.cities, searchTerm);
const expanded = matchingCities.length > 0;
- const match = search(country.code, searchTerm) || search(country.name, searchTerm);
+ const match = search(searchTerm, country.code) || search(searchTerm, country.name);
const resultingCities = match ? country.cities : matchingCities;
return expanded || match ? [...countries, { ...country, cities: resultingCities }] : countries;
}, [] as Array<IRelayLocationRedux>);
@@ -102,7 +105,7 @@ function searchCities(
return cities.reduce((cities, city) => {
const matchingRelays = city.relays.filter((relay) => search(searchTerm, relay.hostname));
const expanded = matchingRelays.length > 0;
- const match = search(city.code, searchTerm) || search(city.name, searchTerm);
+ const match = search(searchTerm, city.code) || search(searchTerm, city.name);
const resultingRelays = match ? city.relays : matchingRelays;
return expanded || match ? [...cities, { ...city, relays: resultingRelays }] : cities;
}, [] as Array<IRelayLocationCityRedux>);
@@ -118,8 +121,11 @@ export function getLocationsExpandedBySearch(
country.code,
searchTerm,
);
+ const cityMatches = country.cities.some(
+ (city) => search(searchTerm, city.code) || search(searchTerm, city.name),
+ );
const location = { country: country.code };
- const expanded = cityLocations.length > 0;
+ const expanded = cityMatches || cityLocations.length > 0;
return expanded ? [...locations, ...cityLocations, location] : locations;
}, [] as Array<RelayLocation>);
}
diff --git a/gui/src/renderer/lib/utilityHooks.ts b/gui/src/renderer/lib/utilityHooks.ts
index 378a6d5ae5..4c66937393 100644
--- a/gui/src/renderer/lib/utilityHooks.ts
+++ b/gui/src/renderer/lib/utilityHooks.ts
@@ -65,3 +65,28 @@ export function useNormalBridgeSettings() {
const bridgeSettings = useSelector((state) => state.settings.bridgeSettings);
return 'normal' in bridgeSettings ? bridgeSettings.normal : undefined;
}
+
+const sharedMemoData: Record<
+ string,
+ { value: unknown; dependencies: Array<unknown> | undefined }
+> = {};
+export function useSharedMemo<T>(
+ key: string,
+ factory: () => T,
+ dependencies: Array<unknown> | undefined,
+): T {
+ const data = sharedMemoData[key];
+ if (
+ data === undefined ||
+ data.dependencies === undefined ||
+ dependencies === undefined ||
+ data.dependencies.length !== dependencies.length ||
+ data.dependencies.some((item, i) => item !== dependencies[i])
+ ) {
+ const value = factory();
+ sharedMemoData[key] = { value, dependencies };
+ return value;
+ } else {
+ return data.value as T;
+ }
+}