Skip to content

Commit

Permalink
perf: Do not query themes and organizations separately
Browse files Browse the repository at this point in the history
  • Loading branch information
bprusinowski committed Oct 31, 2023
1 parent 056c640 commit 28b1dea
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 352 deletions.
34 changes: 2 additions & 32 deletions app/browser/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ import Link from "next/link";
import { Router, useRouter } from "next/router";
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";

import {
SearchCubeResultOrder,
useOrganizationsQuery,
useThemesQuery,
} from "@/graphql/query-hooks";
import { useLocale } from "@/locales/use-locale";
import { SearchCubeResultOrder } from "@/graphql/query-hooks";
import { BrowseParams } from "@/pages/browse";
import { useDataSourceStore } from "@/stores/data-source";
import useEvent from "@/utils/use-event";

import { getFiltersFromParams } from "./filters";
Expand Down Expand Up @@ -114,18 +108,14 @@ const useQueryParamsState = <T extends object>(
};

export const useBrowseState = () => {
const { dataSource } = useDataSourceStore();
const locale = useLocale();
const inputRef = useRef<HTMLInputElement>(null);

const [browseParams, setParams] = useQueryParamsState(
{},
{
parse: getBrowseParamsFromQuery,
serialize: buildURLFromBrowseState,
}
);

const {
search,
type,
Expand All @@ -135,29 +125,9 @@ export const useBrowseState = () => {
dataset: paramDataset,
} = browseParams;

const [{ data: themeData }] = useThemesQuery({
variables: {
sourceType: dataSource.type,
sourceUrl: dataSource.url,
locale,
},
pause: !!paramDataset,
});
const [{ data: orgData }] = useOrganizationsQuery({
variables: {
sourceType: dataSource.type,
sourceUrl: dataSource.url,
locale,
},
pause: !!paramDataset,
});

// Support /browse?dataset=<iri> and legacy /browse/dataset/<iri>
const dataset = type === "dataset" ? iri : paramDataset;
const filters = getFiltersFromParams(browseParams, {
themes: themeData?.themes,
organizations: orgData?.organizations,
});
const filters = getFiltersFromParams(browseParams);

const setSearch = useEvent((v: string) => setParams({ search: v }));
const setIncludeDrafts = useEvent((v: boolean) =>
Expand Down
24 changes: 4 additions & 20 deletions app/browser/dataset-browse.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import { DataCubeOrganization, DataCubeTheme } from "@/graphql/query-hooks";
import { BrowseParams } from "@/pages/browse";

import { getFiltersFromParams } from "./filters";

const ctx = {
themes: [
{
iri: "https://fake-iri-theme",
__typename: "DataCubeTheme",
},
] as DataCubeTheme[],
organizations: [
{
iri: "https://fake-iri-organization",
__typename: "DataCubeOrganization",
},
] as DataCubeOrganization[],
};

describe("getFiltersFromParams", () => {
it("should work only for organization", () => {
const params = {
type: "organization",
iri: "https://fake-iri-organization",
} as BrowseParams;
const filters = getFiltersFromParams(params, ctx);
const filters = getFiltersFromParams(params);
expect(filters).toEqual([
{
__typename: "DataCubeOrganization",
Expand All @@ -40,7 +24,7 @@ describe("getFiltersFromParams", () => {
subtype: "organization",
subiri: "https://fake-iri-organization",
} as BrowseParams;
const filters = getFiltersFromParams(params, ctx);
const filters = getFiltersFromParams(params);
expect(filters).toEqual([
{ iri: "https://fake-iri-theme", __typename: "DataCubeTheme" },
{
Expand All @@ -57,7 +41,7 @@ describe("getFiltersFromParams", () => {
subtype: "theme",
subiri: "https://fake-iri-theme",
} as BrowseParams;
const filters = getFiltersFromParams(params, ctx);
const filters = getFiltersFromParams(params);
expect(filters).toEqual([
{
iri: "https://fake-iri-organization",
Expand All @@ -72,7 +56,7 @@ describe("getFiltersFromParams", () => {
type: "dataset",
iri: "https://fake-iri-dataset",
} as BrowseParams;
const filters = getFiltersFromParams(params, ctx);
const filters = getFiltersFromParams(params);
expect(filters).toEqual([]);
});
});
57 changes: 18 additions & 39 deletions app/browser/dataset-browse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ import {
DataCubeTheme,
SearchCubeResultOrder,
SearchCubesQuery,
useOrganizationsQuery,
useThemesQuery,
} from "@/graphql/query-hooks";
import {
DataCubePublicationStatus,
Expand All @@ -49,8 +47,6 @@ import {
import SvgIcCategories from "@/icons/components/IcCategories";
import SvgIcClose from "@/icons/components/IcClose";
import SvgIcOrganisations from "@/icons/components/IcOrganisations";
import { useLocale } from "@/locales/use-locale";
import { useDataSourceStore } from "@/stores/data-source";
import isAttrEqual from "@/utils/is-attr-equal";
import useEvent from "@/utils/use-event";

Expand Down Expand Up @@ -525,6 +521,7 @@ const NavSection = ({
);
}, [counts, items]);
const { isOpen, open, close } = useDisclosure();

return (
<div>
<NavSectionTitle theme={theme} sx={{ mb: "block" }}>
Expand All @@ -545,7 +542,7 @@ const NavSection = ({
return (
<Reorder.Item drag={false} value={item} key={item.iri} as="div">
<NavItem
active={currentFilter === item}
active={currentFilter?.iri === item.iri}
filters={filters}
next={item}
count={counts[item.iri]}
Expand Down Expand Up @@ -593,27 +590,16 @@ const NavSection = ({
);
};

export const SearchFilters = ({ cubes }: { cubes: SearchCubeResult[] }) => {
const { dataSource } = useDataSourceStore();
const locale = useLocale();
const { filters, dataset } = useBrowseContext();
const [{ data: allThemes }] = useThemesQuery({
variables: {
sourceType: dataSource.type,
sourceUrl: dataSource.url,
locale,
},
pause: !!dataset,
});
const [{ data: allOrgs }] = useOrganizationsQuery({
variables: {
sourceType: dataSource.type,
sourceUrl: dataSource.url,
locale,
},
pause: !!dataset,
});

export const SearchFilters = ({
cubes,
themes,
orgs,
}: {
cubes: SearchCubeResult[];
themes: DataCubeTheme[];
orgs: DataCubeOrganization[];
}) => {
const { filters } = useBrowseContext();
const counts = useMemo(() => {
const result: Record<string, number> = {};

Expand All @@ -639,14 +625,7 @@ export const SearchFilters = ({ cubes }: { cubes: SearchCubeResult[] }) => {
isAttrEqual("__typename", "DataCubeOrganization")
);

const [allThemesAlpha, allOrgsAlpha] = useMemo(() => {
return [
allThemes ? sortBy(allThemes.themes, (x) => x?.label) : null,
allOrgs ? sortBy(allOrgs.organizations, (x) => x?.label) : null,
];
}, [allThemes, allOrgs]);

const displayedThemes = allThemesAlpha?.filter((theme) => {
const displayedThemes = themes.filter((theme) => {
if (!theme.label) {
return false;
}
Expand All @@ -655,23 +634,23 @@ export const SearchFilters = ({ cubes }: { cubes: SearchCubeResult[] }) => {
return false;
}

if (themeFilter && themeFilter !== theme) {
if (themeFilter && themeFilter.iri !== theme.iri) {
return false;
}

return true;
});

const displayedOrgs = allOrgsAlpha?.filter((org) => {
const displayedOrgs = orgs.filter((org) => {
if (!org.label) {
return false;
}

if (!counts[org.iri] && orgFilter !== org) {
if (!counts[org.iri] && orgFilter?.iri !== org.iri) {
return false;
}

if (orgFilter && orgFilter !== org) {
if (orgFilter && orgFilter.iri !== org.iri) {
return false;
}

Expand Down Expand Up @@ -721,7 +700,7 @@ export const SearchFilters = ({ cubes }: { cubes: SearchCubeResult[] }) => {
icon={<SvgIcOrganisations width={20} height={20} />}
label={<Trans id="browse-panel.organizations">Organizations</Trans>}
extra={
orgFilter && filters.includes(orgFilter) ? (
orgFilter && filters.map((d) => d.iri).includes(orgFilter.iri) ? (
<Subthemes
subthemes={subthemes}
filters={filters}
Expand Down
29 changes: 7 additions & 22 deletions app/browser/filters.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
DataCubeOrganization,
DataCubeTheme,
OrganizationsQuery,
ThemesQuery,
} from "@/graphql/query-hooks";
import { DataCubeOrganization, DataCubeTheme } from "@/graphql/query-hooks";
import { BrowseParams } from "@/pages/browse";

export type DataCubeAbout = {
Expand All @@ -14,31 +9,21 @@ export type DataCubeAbout = {
export type BrowseFilter = DataCubeTheme | DataCubeOrganization | DataCubeAbout;
/** Builds the state search filters from query params */

export const getFiltersFromParams = (
params: BrowseParams,
context: {
themes?: ThemesQuery["themes"];
organizations?: OrganizationsQuery["organizations"];
}
) => {
export const getFiltersFromParams = (params: BrowseParams) => {
const filters: BrowseFilter[] = [];
const { type, subtype, iri, subiri, topic } = params;
for (const [t, i] of [
[type, iri],
[subtype, subiri],
]) {
if (t && i && (t === "theme" || t === "organization")) {
const container = context[
t === "theme" ? "themes" : "organizations"
] as BrowseFilter[];
const obj = container?.find((f) => i === f.iri);
if (obj) {
filters.push(obj);
} else {
break;
}
filters.push({
__typename: t === "theme" ? "DataCubeTheme" : "DataCubeOrganization",
iri: i,
});
}
}

if (topic) {
filters.push({
__typename: "DataCubeAbout",
Expand Down
48 changes: 45 additions & 3 deletions app/browser/select-dataset-step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { t, Trans } from "@lingui/macro";
import { Box, Button, Theme, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { AnimatePresence } from "framer-motion";
import sortBy from "lodash/sortBy";
import uniqBy from "lodash/uniqBy";
import Head from "next/head";
import NextLink from "next/link";
import { Router, useRouter } from "next/router";
Expand Down Expand Up @@ -32,7 +34,12 @@ import {
PanelLeftWrapper,
PanelMiddleWrapper,
} from "@/configurator/components/layout";
import { useSearchCubesQuery } from "@/graphql/query-hooks";
import { truthy } from "@/domain/types";
import {
DataCubeOrganization,
DataCubeTheme,
useSearchCubesQuery,
} from "@/graphql/query-hooks";
import { Icon } from "@/icons";
import { useConfiguratorState, useLocale } from "@/src";

Expand Down Expand Up @@ -206,6 +213,32 @@ const SelectDatasetStepContent = () => {
};
}, [data, filters]);

const themes: DataCubeTheme[] = React.useMemo(() => {
return sortBy(
uniqBy(
cubes
.flatMap((d) => d.cube.themes)
.map((d) => ({ ...d, __typename: "DataCubeTheme" })),
(d) => d.iri
),
(d) => d.label
);
}, [cubes]);

const orgs: DataCubeOrganization[] = React.useMemo(() => {
return sortBy(
uniqBy(
cubes
.map((d) => d.cube.creator)
.filter((d) => d?.iri)
.filter(truthy)
.map((d) => ({ ...d, __typename: "DataCubeOrganization" })),
(d) => d.iri
),
(d) => d.label
);
}, [cubes]);

if (configState.state !== "SELECTING_DATASET") {
return null;
}
Expand Down Expand Up @@ -280,7 +313,7 @@ const SelectDatasetStepContent = () => {
</MotionBox>
) : (
<MotionBox key="search-filters" {...navPresenceProps}>
<SearchFilters cubes={allCubes} />
<SearchFilters cubes={allCubes} themes={themes} orgs={orgs} />
</MotionBox>
)}
</AnimatePresence>
Expand Down Expand Up @@ -329,7 +362,16 @@ const SelectDatasetStepContent = () => {
className={classes.filters}
variant="h1"
>
{queryFilters.map((d) => d.label).join(", ")}
{queryFilters
.map((d) => {
const searchList =
d.type === "DataCubeTheme" ? themes : orgs;
const item = searchList.find(

Check failure on line 369 in app/browser/select-dataset-step.tsx

View workflow job for this annotation

GitHub Actions / lint

This expression is not callable.
({ iri }) => iri === d.value

Check failure on line 370 in app/browser/select-dataset-step.tsx

View workflow job for this annotation

GitHub Actions / lint

Binding element 'iri' implicitly has an 'any' type.
);
return (item ?? d).label;
})
.join(", ")}
</Typography>
</MotionBox>
)}
Expand Down
Loading

0 comments on commit 28b1dea

Please sign in to comment.