Skip to content

Commit

Permalink
feat: Default sort order is newest, when a search is made, it switche…
Browse files Browse the repository at this point in the history
…s to relevance
  • Loading branch information
ptbrowne committed Oct 27, 2022
1 parent 018b9c4 commit 06061b1
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 44 deletions.
33 changes: 16 additions & 17 deletions app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BoxProps,
ButtonBase,
Checkbox as MUICheckbox,
InputProps,
FormControlLabel,
Input as MUIInput,
Radio as MUIRadio,
Expand Down Expand Up @@ -340,6 +341,7 @@ export const MinimalisticSelect = ({
onChange,
smaller = false,
disabled,
...props
}: {
id: string;
options: Option[];
Expand Down Expand Up @@ -379,6 +381,7 @@ export const MinimalisticSelect = ({
onChange={onChange}
value={value}
disabled={disabled}
{...props}
>
{options.map((opt) => (
<option key={opt.value} value={opt.value || undefined}>
Expand Down Expand Up @@ -509,32 +512,30 @@ export const SearchField = ({
value,
defaultValue,
placeholder,
onKeyPress,
onReset,
onFocus,
onBlur,
sx,
inputRef,
InputProps,
}: {
id: string;
label?: string | ReactNode;
disabled?: boolean;
defaultValue?: string;
placeholder?: string;
onKeyPress?: (ev: React.KeyboardEvent<HTMLInputElement>) => void;
onReset?: () => void;
onFocus?: () => void;
onBlur?: () => void;
InputProps: InputProps;
inputRef?: React.RefObject<HTMLInputElement>;
sx?: BoxProps["sx"];
} & FieldProps) => {
const { search } = useBrowseContext();
const handleReset = useCallback(() => {
if (inputRef?.current) {
inputRef.current.value = "";
}
onReset?.();
}, [inputRef, onReset]);
const { onReset } = InputProps;
const handleReset = useCallback(
(ev) => {
if (inputRef?.current) {
inputRef.current.value = "";
}
onReset?.(ev);
},
[inputRef, onReset]
);
return (
<Box
sx={{ color: "grey.700", fontSize: "1rem", position: "relative", ...sx }}
Expand All @@ -549,10 +550,8 @@ export const SearchField = ({
id={id}
value={value}
defaultValue={defaultValue}
onKeyPress={onKeyPress}
{...InputProps}
placeholder={placeholder}
onFocus={onFocus}
onBlur={onBlur}
autoComplete="off"
inputRef={inputRef}
sx={{ width: "100%", input: { borderRadius: 2 } }}
Expand Down
18 changes: 13 additions & 5 deletions app/configurator/components/dataset-browse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export const useBrowseState = () => {
search: newSearch,
order:
newSearch === ""
? DataCubeResultOrder.TitleAsc
? DataCubeResultOrder.CreatedDesc
: previousOrderRef.current,
});
},
Expand Down Expand Up @@ -330,9 +330,11 @@ export const SearchDatasetBox = ({
onReset,
includeDrafts,
setIncludeDrafts,
order,
order: stateOrder,
onSetOrder,
} = browseState;

const order = stateOrder || DataCubeResultOrder.CreatedDesc;
const options = [
{
value: DataCubeResultOrder.Score,
Expand Down Expand Up @@ -384,10 +386,15 @@ export const SearchDatasetBox = ({
id="datasetSearch"
label={searchLabel}
defaultValue={search || ""}
onKeyPress={handleKeyPress}
onReset={onReset}
InputProps={{
inputProps: {
"data-testid": "datasetSearch",
},
onKeyPress: handleKeyPress,
onReset: onReset,
onFocus: () => setShowDraftCheckbox(true),
}}
placeholder={placeholderLabel}
onFocus={() => setShowDraftCheckbox(true)}
sx={{ flexGrow: 1 }}
/>
</Box>
Expand Down Expand Up @@ -442,6 +449,7 @@ export const SearchDatasetBox = ({
id="datasetSort"
smaller={true}
value={order}
data-testid="datasetSort"
options={isSearching ? options : options.slice(1)}
onChange={(e) => {
onSetOrder(e.target.value as DataCubeResultOrder);
Expand Down
49 changes: 32 additions & 17 deletions app/graphql/resolvers/rdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
QueryResolvers,
Resolvers,
} from "@/graphql/resolver-types";
import { ResolvedDataCube } from "@/graphql/shared-types";
import { parseLocaleString } from "@/locales/locales";
import { createSource } from "@/rdf/create-source";
import {
Expand All @@ -33,7 +32,37 @@ import {
} from "@/rdf/query-cube-metadata";
import { unversionObservation } from "@/rdf/query-dimension-values";
import { queryHierarchy } from "@/rdf/query-hierarchies";
import { searchCubes } from "@/rdf/query-search";
import { SearchResult, searchCubes } from "@/rdf/query-search";

const sortResults = (
results: SearchResult[],
order: DataCubeResultOrder | undefined | null,
locale: string | undefined | null
): SearchResult[] => {
const getCube = (r: SearchResult) => r.dataCube.data;
switch (order) {
case DataCubeResultOrder.TitleAsc:
results.sort((a, b) =>
getCube(a).title.localeCompare(getCube(b).title, locale ?? undefined)
);
break;
case DataCubeResultOrder.CreatedDesc:
case undefined:
case null:
results.sort((a, b) => {
const ra = getCube(a).datePublished || "0";
const rb = getCube(b).datePublished || "0";
return descending(ra, rb);
});
break;
case DataCubeResultOrder.Score:
break;
default:
const exhaustCheck = order;
return exhaustCheck;
}
return results;
};

export const dataCubes: NonNullable<QueryResolvers["dataCubes"]> = async (
_,
Expand All @@ -42,20 +71,6 @@ export const dataCubes: NonNullable<QueryResolvers["dataCubes"]> = async (
info
) => {
const { sparqlClient, sparqlClientStream } = await setup(info);
const sortResults = <T extends unknown[]>(
results: T,
getter: (d: T[number]) => ResolvedDataCube["data"]
) => {
if (order === DataCubeResultOrder.TitleAsc) {
results.sort((a: any, b: any) =>
getter(a).title.localeCompare(getter(b).title, locale ?? undefined)
);
} else if (order === DataCubeResultOrder.CreatedDesc) {
results.sort((a: any, b: any) =>
descending(getter(a).datePublished, getter(b).datePublished)
);
}
};

const { candidates, meta } = await searchCubes({
locale,
Expand All @@ -70,7 +85,7 @@ export const dataCubes: NonNullable<QueryResolvers["dataCubes"]> = async (
queries.push(query);
}

sortResults(candidates, (x) => x.dataCube.data);
sortResults(candidates, order, locale);
return candidates;
};

Expand Down
4 changes: 4 additions & 0 deletions app/rdf/query-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,7 @@ export const searchCubes = async ({
},
};
};

export type SearchResult = Awaited<
ReturnType<typeof searchCubes>
>["candidates"][0];
37 changes: 33 additions & 4 deletions e2e/search.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { within } from "@playwright-testing-library/test";
import { Locator } from "@playwright/test";

import { test, expect } from "./common";

const getSelectValue = async (locator: Locator) => {
return locator.evaluate((ev) => (ev as HTMLSelectElement).value);
};

test("should be possible to open a search URL, and search state should be recovered", async ({
page,
screen,
selectors,
}) => {
const ctx = { page, screen };

test.slow();

page.goto(
await page.goto(
`/en/browse?includeDrafts=true&order=SCORE&search=category&dataSource=Int`
);
await selectors.search.resultsCount();

expect(await selectors.search.searchInput().getAttribute("value")).toEqual(
"category"
Expand Down Expand Up @@ -55,3 +58,29 @@ test("search results count coherence", async ({ page, screen, selectors }) => {
await page.locator(`:text("${count} results")`).waitFor({ timeout: 10000 });
}
});

test("sort order", async ({ page, selectors, screen }) => {
await page.goto("/en/browse?dataSource=Int");
const resultCount = await selectors.search.resultsCount();
const text = await resultCount.textContent();
const select = selectors.search.datasetSort().locator("select");

expect(await getSelectValue(select)).toBe("CREATED_DESC");

const searchInput = screen.getAllByPlaceholderText(
"Name, description, organization, theme, keyword"
);

await searchInput.type("NFI");
await page.keyboard.press("Enter");
expect(await getSelectValue(select)).toBe("SCORE");

await searchInput.selectText();
await page.keyboard.press("Delete");
await page.keyboard.press("Enter");
expect(await getSelectValue(select)).toBe("CREATED_DESC");

await searchInput.type("NFI");
await page.keyboard.press("Enter");
expect(await getSelectValue(select)).toBe("SCORE");
});
3 changes: 2 additions & 1 deletion e2e/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ export const createSelectors = ({ screen, page, within }: Ctx) => {
options: () => page.locator('li[role="option"]'),
},
search: {
searchInput: () => page.locator("#datasetSearch"),
searchInput: () => screen.getByTestId("datasetSearch"),
draftsCheckbox: () => page.locator("#dataset-include-drafts"),
datasetSort: () => screen.getByTestId("datasetSort"),
navItem: () => screen.findByTestId("navItem"),
navChip: () => screen.findByTestId("navChip"),
resultsCount: () =>
Expand Down

0 comments on commit 06061b1

Please sign in to comment.