Skip to content

Commit

Permalink
Fix calculated properties when searching in relay list
Browse files Browse the repository at this point in the history
  • Loading branch information
raksooo committed Oct 5, 2023
1 parent 3e73c09 commit 7fe914e
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default function CustomLists(props: CustomListsProps) {
hideAddList();
}, []);

if (searchTerm !== '' && customLists.length === 0) {
if (searchTerm !== '' && !customLists.some((list) => list.visible)) {
return null;
}

Expand Down
17 changes: 11 additions & 6 deletions gui/src/renderer/components/select-location/LocationRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ interface IProps<C extends LocationSpecification> {

// Renders the rows and its children for countries, cities and relays
function LocationRow<C extends LocationSpecification>(props: IProps<C>) {
const hasChildren = React.Children.count(props.children) > 0;
const hasChildren = getLocationChildren(props.source).some((child) => child.visible);
const buttonRef = useRef<HTMLButtonElement>() as React.RefObject<HTMLButtonElement>;
const userInvokedExpand = useRef(false);

Expand Down Expand Up @@ -204,6 +204,10 @@ function LocationRow<C extends LocationSpecification>(props: IProps<C>) {
}
}, [props.source.location.customList]);

if (!props.source.visible) {
return null;
}

// The selectedRef should only be used if the element is selected
const selectedRef = props.source.selected ? props.selectedElementRef : undefined;
return (
Expand Down Expand Up @@ -329,6 +333,7 @@ function compareLocation(
nextLocation: LocationSpecification,
): boolean {
return (
oldLocation.visible === nextLocation.visible &&
oldLocation.label === nextLocation.label &&
oldLocation.active === nextLocation.active &&
oldLocation.disabled === nextLocation.disabled &&
Expand All @@ -343,16 +348,16 @@ function compareChildren(
oldLocation: LocationSpecification,
nextLocation: LocationSpecification,
): boolean {
const oldChildren = getLocationChildren(oldLocation);
const nextChildren = getLocationChildren(nextLocation);
const oldVisibleChildren = getLocationChildren(oldLocation).filter((child) => child.visible);
const nextVisibleChildren = getLocationChildren(nextLocation).filter((child) => child.visible);

// Children shouldn't be checked if the row is collapsed
const nextExpanded = 'expanded' in nextLocation && nextLocation.expanded;

return (
(!nextExpanded && oldChildren.length > 0 && nextChildren.length > 0) ||
(oldChildren.length === nextChildren.length &&
oldChildren.every((oldChild, i) => compareLocation(oldChild, nextChildren[i])))
(!nextExpanded && oldVisibleChildren.length > 0 && nextVisibleChildren.length > 0) ||
(oldVisibleChildren.length === nextVisibleChildren.length &&
oldVisibleChildren.every((oldChild, i) => compareLocation(oldChild, nextVisibleChildren[i])))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
DisabledReason,
GeographicalRelayList,
LocationType,
RelayLocationCountryWithVisibility,
} from './select-location-types';
import { useSelectLocationContext } from './SelectLocationContainer';

Expand Down Expand Up @@ -127,7 +128,7 @@ export function RelayListContextProvider(props: RelayListContextProviderProps) {
// Return the final filtered and formatted relay list. This should be the only place in the app
// where processing of the relay list is performed.
function useRelayList(
relayList: Array<IRelayLocationCountryRedux>,
relayList: Array<RelayLocationCountryWithVisibility>,
expandedLocations?: Array<RelayLocation>,
): GeographicalRelayList {
const locale = useSelector((state) => state.userInterface.locale);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ function LocationList<T>(props: CombinedLocationListProps<T>) {

if (
searchTerm !== '' &&
props.relayLocations.length === 0 &&
!props.relayLocations.some((country) => country.visible) &&
(props.specialLocations === undefined || props.specialLocations.length === 0)
) {
return null;
Expand All @@ -381,8 +381,8 @@ function NoSearchResult(props: NoSearchResultProps) {

if (
searchTerm === '' ||
relayList.length > 0 ||
customLists.length > 0 ||
relayList.some((country) => country.visible) ||
customLists.some((list) => list.visible) ||
props.specialLocationsLength > 0
) {
return null;
Expand All @@ -393,7 +393,7 @@ function NoSearchResult(props: NoSearchResultProps) {
<StyledNoResultText>
{formatHtml(
sprintf(messages.gettext('No result for <b>%(searchTerm)s</b>.'), {
searchTerm: searchTerm,
searchTerm,
}),
)}
</StyledNoResultText>
Expand Down
20 changes: 15 additions & 5 deletions gui/src/renderer/components/select-location/custom-list-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ export function useCustomListsRelayList(
// Populate all custom lists with the real location trees for the list locations.
return useMemo(
() =>
customLists
.map((list) =>
prepareCustomList(list, relayList, selectedLocation, disabledLocation, expandedLocations),
)
.filter((list) => searchMatch(searchTerm, list.label)),
customLists.map((list) =>
prepareCustomList(
list,
relayList,
searchTerm,
selectedLocation,
disabledLocation,
expandedLocations,
),
),
[customLists, relayList, selectedLocation, disabledLocation, expandedLocations],
);
}
Expand All @@ -41,6 +46,7 @@ export function useCustomListsRelayList(
function prepareCustomList(
list: ICustomList,
fullRelayList: GeographicalRelayList,
searchTerm: string,
selectedLocation?: RelayLocation,
disabledLocation?: { location: RelayLocation; reason: DisabledReason },
expandedLocations?: Array<RelayLocation>,
Expand All @@ -59,6 +65,7 @@ function prepareCustomList(
disabledReason,
expanded: isExpanded(location, expandedLocations),
selected: isSelected(location, selectedLocation),
visible: searchMatch(searchTerm, list.name),
locations,
};
}
Expand Down Expand Up @@ -121,6 +128,7 @@ function updateCountry(
location,
expanded: isExpanded(location, expandedLocations),
selected: false,
visible: true,
cities: country.cities.map((city) =>
updateCity(city, customList, locationCounter, expandedLocations),
),
Expand All @@ -147,6 +155,7 @@ function updateCity(
location,
expanded: isExpanded(location, expandedLocations),
selected: false,
visible: true,
relays: city.relays.map((relay) => updateRelay(relay, customList)),
};
}
Expand All @@ -158,6 +167,7 @@ function updateRelay(relay: RelaySpecification, customList: string): RelaySpecif
...relay,
location: { ...relay.location, customList },
selected: false,
visible: true,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export enum SpecialLocationIcon {
geoLocation = 'icon-nearest',
}

export interface LocationVisibility {
visible: boolean;
}

interface CommonLocationSpecification {
label: string;
selected: boolean;
Expand All @@ -48,10 +52,25 @@ type GeographicalLocationSpecification =

export type LocationSpecification = GeographicalLocationSpecification | CustomListSpecification;

interface CommonNormalLocationSpecification extends CommonLocationSpecification {
export interface RelayLocationCountryWithVisibility
extends IRelayLocationCountryRedux,
LocationVisibility {
cities: Array<RelayLocationCityWithVisibility>;
}

export interface RelayLocationCityWithVisibility
extends IRelayLocationCityRedux,
LocationVisibility {
relays: Array<RelayLocationRelayWithVisibility>;
}

export type RelayLocationRelayWithVisibility = IRelayLocationRelayRedux & LocationVisibility;

interface CommonNormalLocationSpecification
extends CommonLocationSpecification,
LocationVisibility {
location: RelayLocation;
disabled: boolean;
selected: boolean;
active: boolean;
}

Expand Down
52 changes: 33 additions & 19 deletions gui/src/renderer/lib/filter-locations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Ownership, RelayEndpointType, RelayLocation } from '../../shared/daemon-rpc-types';
import { relayLocations } from '../../shared/gettext';
import { SpecialLocation } from '../components/select-location/select-location-types';
import {
RelayLocationCityWithVisibility,
RelayLocationCountryWithVisibility,
RelayLocationRelayWithVisibility,
SpecialLocation,
} from '../components/select-location/select-location-types';
import {
IRelayLocationCityRedux,
IRelayLocationCountryRedux,
Expand Down Expand Up @@ -90,35 +95,44 @@ function filterLocationsImpl(
export function searchForLocations(
countries: Array<IRelayLocationCountryRedux>,
searchTerm: string,
): Array<IRelayLocationCountryRedux> {
if (searchTerm === '') {
return countries;
}

return countries.reduce((countries, country) => {
const matchingCities = searchCities(country.cities, searchTerm);
const expanded = matchingCities.length > 0;
): Array<RelayLocationCountryWithVisibility> {
return countries.map((country) => {
const match =
searchTerm === '' ||
searchMatch(searchTerm, country.code) ||
searchMatch(searchTerm, relayLocations.gettext(country.name));
const resultingCities = match ? country.cities : matchingCities;
return expanded || match ? [...countries, { ...country, cities: resultingCities }] : countries;
}, [] as Array<IRelayLocationCountryRedux>);
const cities = searchCities(country.cities, searchTerm, match);
const expanded = cities.some((city) => city.visible);
return { ...country, cities: cities, visible: expanded || match };
});
}

function searchCities(
cities: Array<IRelayLocationCityRedux>,
searchTerm: string,
): Array<IRelayLocationCityRedux> {
return cities.reduce((cities, city) => {
const matchingRelays = city.relays.filter((relay) => searchMatch(searchTerm, relay.hostname));
const expanded = matchingRelays.length > 0;
countryMatch: boolean,
): Array<RelayLocationCityWithVisibility> {
return cities.map((city) => {
const match =
searchTerm === '' ||
countryMatch ||
searchMatch(searchTerm, city.code) ||
searchMatch(searchTerm, relayLocations.gettext(city.name));
const resultingRelays = match ? city.relays : matchingRelays;
return expanded || match ? [...cities, { ...city, relays: resultingRelays }] : cities;
}, [] as Array<IRelayLocationCityRedux>);
const relays = searchRelays(city.relays, searchTerm, match);
const expanded = match || relays.some((relay) => relay.visible);
return { ...city, relays: relays, visible: expanded };
});
}

function searchRelays(
relays: Array<IRelayLocationRelayRedux>,
searchTerm: string,
cityMatch: boolean,
): Array<RelayLocationRelayWithVisibility> {
return relays.map((relay) => ({
...relay,
visible: searchTerm === '' || cityMatch || searchMatch(searchTerm, relay.hostname),
}));
}

export function getLocationsExpandedBySearch(
Expand Down

0 comments on commit 7fe914e

Please sign in to comment.