Skip to content

Commit

Permalink
Add catalog filter (#448)
Browse files Browse the repository at this point in the history
* Add organization_siret filter to API

* Add "Catalogue" filter to frontend

* Switch to get-all rather than get-all-non-empty

* Address feedback
  • Loading branch information
florimondmanca committed Sep 26, 2022
1 parent 59f7ed7 commit d694238
Show file tree
Hide file tree
Showing 18 changed files with 196 additions and 21 deletions.
3 changes: 3 additions & 0 deletions client/src/definitions/datasetFilters.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { SelectOption } from "./form";
import type { Organization } from "./organizations";
import type { Tag } from "./tag";

export type DatasetFiltersInfo = {
organizationSiret: Organization[];
geographicalCoverage: string[];
service: string[];
format: string[];
Expand All @@ -11,6 +13,7 @@ export type DatasetFiltersInfo = {
};

export type DatasetFiltersValue = {
organizationSiret: string | null;
geographicalCoverage: string | null;
service: string | null;
format: string | null;
Expand Down
6 changes: 5 additions & 1 deletion client/src/lib/transformers/datasetFilters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {

describe("transformers -- Dataset filters", () => {
const info: DatasetFiltersInfo = {
organizationSiret: [{ siret: "ign_siret", name: "IGN" }],
geographicalCoverage: [
"Métropole Européenne de Lille",
"France métropolitaine",
Expand All @@ -33,6 +34,7 @@ describe("transformers -- Dataset filters", () => {
};

const value: DatasetFiltersValue = {
organizationSiret: "ign_siret",
geographicalCoverage: "France métropolitaine",
format: "file_gis",
service: null,
Expand All @@ -43,6 +45,7 @@ describe("transformers -- Dataset filters", () => {

test("toFiltersParams", () => {
const params = [
["organization_siret", "ign_siret"],
["geographical_coverage", "France métropolitaine"],
["service", null],
["format", "file_gis"],
Expand All @@ -57,13 +60,14 @@ describe("transformers -- Dataset filters", () => {
test("getFiltersValueFromParams", () => {
const queryString = toQueryString(toFiltersParams(value));
expect(queryString).toBe(
"?geographical_coverage=France+m%C3%A9tropolitaine&format=file_gis&technical_source=Serveur+GIS&license=Licence+Ouverte"
"?organization_siret=ign_siret&geographical_coverage=France+m%C3%A9tropolitaine&format=file_gis&technical_source=Serveur+GIS&license=Licence+Ouverte"
);
expect(toFiltersValue(new URLSearchParams(queryString))).toEqual(value);
});

test("toFiltersOptions", () => {
const options: DatasetFiltersOptions = {
organizationSiret: [{ label: "IGN", value: "ign_siret" }],
geographicalCoverage: [
{
label: "Métropole Européenne de Lille",
Expand Down
21 changes: 20 additions & 1 deletion client/src/lib/transformers/datasetFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ import type { QueryParamRecord } from "src/definitions/url";
import { Maybe } from "../util/maybe";

export const toFiltersInfo = (data: any): DatasetFiltersInfo => {
const { geographical_coverage, technical_source, tag_id, ...rest } = data;
const {
organization_siret,
geographical_coverage,
technical_source,
tag_id,
...rest
} = data;
return {
organizationSiret: organization_siret,
geographicalCoverage: geographical_coverage,
technicalSource: technical_source,
tagId: tag_id,
Expand All @@ -21,6 +28,7 @@ export const toFiltersValue = (
searchParams: URLSearchParams
): DatasetFiltersValue => {
return {
organizationSiret: searchParams.get("organization_siret"),
geographicalCoverage: searchParams.get("geographical_coverage"),
service: searchParams.get("service"),
format: searchParams.get("format"),
Expand All @@ -34,6 +42,7 @@ export const toFiltersParams = (
value: DatasetFiltersValue
): QueryParamRecord => {
const {
organizationSiret,
geographicalCoverage,
service,
format,
Expand All @@ -43,6 +52,7 @@ export const toFiltersParams = (
} = value;

return [
["organization_siret", organizationSiret],
["geographical_coverage", geographicalCoverage],
["service", service],
["format", format],
Expand All @@ -56,6 +66,10 @@ export const toFiltersOptions = (
info: DatasetFiltersInfo
): DatasetFiltersOptions => {
return {
organizationSiret: info.organizationSiret.map(({ name, siret }) => ({
label: name,
value: siret,
})),
geographicalCoverage: info.geographicalCoverage.map((value) => ({
label: value,
value,
Expand All @@ -79,9 +93,14 @@ export const toFiltersOptions = (

export const toFiltersButtonTexts = (
value: DatasetFiltersValue,
organizationSiretToName: Record<string, string>,
tagIdToName: Record<string, string>
): { [K in keyof DatasetFiltersValue]: Maybe<string> } => {
return {
organizationSiret: Maybe.map(
value.organizationSiret,
(v) => organizationSiretToName[v]
),
geographicalCoverage: value.geographicalCoverage,
service: value.service,
format: Maybe.map(value.format, (v) => DATA_FORMAT_LABELS[v]),
Expand Down
8 changes: 6 additions & 2 deletions client/src/routes/(app)/fiches/search/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@
<section class="fr-container">
{#if Maybe.Some(paginatedDatasets)}
<div class="fr-grid-row summary">
<div class="fr-col-12 fr-pb-3w summary__header">
<div class="fr-col-12 fr-pb-1w summary__header">
<h2>
{paginatedDatasets.totalItems}
{pluralize(paginatedDatasets.totalItems, "résultat", "résultats")}
{pluralize(
paginatedDatasets.totalItems,
"fiche de données",
"fiches de données"
)}
</h2>

<button
Expand Down
33 changes: 31 additions & 2 deletions client/src/routes/(app)/fiches/search/_FilterPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
DatasetFiltersValue,
} from "src/definitions/datasetFilters";
import type { SelectOption } from "src/definitions/form";
import type { Organization } from "src/definitions/organizations";
import type { Tag } from "src/definitions/tag";
import SearchableSelect from "src/lib/components/SearchableSelect/SearchableSelect.svelte";
import {
Expand All @@ -15,15 +16,30 @@
export let info: DatasetFiltersInfo;
export let value: DatasetFiltersValue;
const createTagIdToNameMap = (tags: Tag[]) => {
const createOrganizationSiretToNameMap = (
organizations: Organization[]
): Record<string, string> => {
const map = {};
organizations.forEach(({ siret, name }) => (map[siret] = name));
return map;
};
const createTagIdToNameMap = (tags: Tag[]): Record<string, string> => {
const map = {};
tags.forEach(({ id, name }) => (map[id] = name));
return map;
};
$: organizationSiretToName = createOrganizationSiretToNameMap(
info.organizationSiret
);
$: tagIdToName = createTagIdToNameMap(info.tagId);
$: filtersOptions = toFiltersOptions(info);
$: buttonTexts = toFiltersButtonTexts(value, tagIdToName);
$: buttonTexts = toFiltersButtonTexts(
value,
organizationSiretToName,
tagIdToName
);
const dispatch = createEventDispatcher<{ change: DatasetFiltersValue }>();
Expand Down Expand Up @@ -71,6 +87,19 @@
options={filtersOptions.license}
/>
</div>

<h6 class="fr-mt-3w">Catalogues</h6>

<div class="fr-mb-2w">
<SearchableSelect
label="Catalogue"
buttonPlaceholder="Rechercher..."
inputPlaceholder="Rechercher..."
buttonText={buttonTexts.organizationSiret || "Rechercher..."}
on:clickItem={(e) => handleSelectFilter("organizationSiret", e)}
options={filtersOptions.organizationSiret}
/>
</div>
</section>

<section>
Expand Down
16 changes: 11 additions & 5 deletions client/src/tests/e2e/search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ test.describe("Search", () => {

await expect(page).toHaveTitle("Rechercher un jeu de données");
await expect(page).toHaveURL("/fiches/search?q=title");
await page.locator(`text=/${items.length} résultat(s)?/i`).waitFor();
await page
.locator(`text=/${items.length} fiche(s)? de données/i`)
.waitFor();
await page.locator(`:has-text('${dataset.title}')`).first().waitFor();
});

Expand Down Expand Up @@ -86,7 +88,9 @@ test.describe("Search", () => {
expect(items[0].title).toBe(dataset.title);

await expect(page).toHaveURL("/fiches/search?q=title&page=1");
await page.locator(`text=/${items.length} résultat(s)?/i`).waitFor();
await page
.locator(`text=/${items.length} fiche(s)? de données/i`)
.waitFor();
await page.locator(`:has-text('${dataset.title}')`).first().waitFor();

// Second search. Aim at getting no results.
Expand All @@ -113,7 +117,7 @@ test.describe("Search", () => {
await page.goto(`/fiches/search?q=${dataset.title}`);
const search = page.locator("form [name=q]");
expect(await search.inputValue()).toBe(dataset.title);
await page.locator(`text=/résultat(s)?/i`).waitFor();
await page.locator(`text=/fiche(s)? de données/i`).waitFor();
await page.locator(`:has-text('${dataset.title}')`).first().waitFor();
});

Expand All @@ -133,15 +137,17 @@ test.describe("Search filters", () => {

const filterPanel = page.locator("[data-test-id='filter-panel']");

expect(await filterPanel.locator("h6").count()).toBe(3);
expect(await filterPanel.locator("h6").count()).toBe(4);
await filterPanel.locator("text=Informations générales").waitFor();
await filterPanel.locator("text=Catalogues").waitFor();
await filterPanel.locator("text=Sources et formats").waitFor();
await filterPanel.locator("text=Mots-clés thématiques").waitFor();

expect(await filterPanel.locator("button").count()).toBe(6);
expect(await filterPanel.locator("button").count()).toBe(7);
await filterPanel.locator("text=Couverture géographique").waitFor();
await filterPanel.locator("text=Service producteur de la donnée").waitFor();
await filterPanel.locator("text=Licence de réutilisation").waitFor();
await filterPanel.locator("text='Catalogue'").waitFor();
await filterPanel.locator("text=Format de mise à disposition").waitFor();
await filterPanel.locator("text=Système d'information source").waitFor();
await filterPanel.locator("text=Mot-clé").waitFor();
Expand Down
1 change: 1 addition & 0 deletions server/api/datasets/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ async def list_datasets(
page=page,
spec=DatasetSpec(
search_term=params.q,
organization_siret=params.organization_siret,
geographical_coverage__in=params.geographical_coverage,
service__in=params.service,
format__in=params.format,
Expand Down
2 changes: 2 additions & 0 deletions server/api/datasets/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def __init__(
q: Optional[str] = None,
page_number: int = 1,
page_size: int = 10,
organization_siret: Optional[Siret] = Query(None),
geographical_coverage: Optional[List[str]] = Query(None),
service: Optional[List[str]] = Query(None),
format_: Optional[List[DataFormat]] = Query(None, alias="format"),
Expand All @@ -29,6 +30,7 @@ def __init__(
license: Optional[str] = Query(None),
) -> None:
self.q = q
self.organization_siret = organization_siret
self.page_number = page_number
self.page_size = page_size
self.geographical_coverage = geographical_coverage
Expand Down
12 changes: 10 additions & 2 deletions server/application/catalogs/handlers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict
from typing import Dict, List

from server.config.di import resolve
from server.domain.catalogs.entities import Catalog
Expand All @@ -10,7 +10,7 @@
from server.domain.organizations.types import Siret

from .commands import CreateCatalog
from .queries import GetCatalogBySiret
from .queries import GetAllCatalogs, GetCatalogBySiret
from .views import CatalogView


Expand All @@ -26,6 +26,14 @@ async def get_catalog_by_siret(query: GetCatalogBySiret) -> CatalogView:
return CatalogView(**catalog.dict())


async def get_all_catalogs(
query: GetAllCatalogs,
) -> List[CatalogView]:
repository = resolve(CatalogRepository)
catalogs = await repository.get_all()
return [CatalogView(**catalog.dict()) for catalog in catalogs]


async def create_catalog(
command: CreateCatalog, *, extra_field_ids_by_name: Dict[str, ID] = None
) -> Siret:
Expand Down
6 changes: 6 additions & 0 deletions server/application/catalogs/queries.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List

from server.domain.organizations.types import Siret
from server.seedwork.application.queries import Query

Expand All @@ -6,3 +8,7 @@

class GetCatalogBySiret(Query[CatalogView]):
siret: Siret


class GetAllCatalogs(Query[List[CatalogView]]):
pass
3 changes: 3 additions & 0 deletions server/application/datasets/handlers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from server.application.catalogs.queries import GetAllCatalogs
from server.application.licenses.queries import GetLicenseSet
from server.application.tags.queries import GetAllTags
from server.config.di import resolve
Expand Down Expand Up @@ -83,13 +84,15 @@ async def get_dataset_filters(query: GetDatasetFilters) -> DatasetFiltersView:
bus = resolve(MessageBus)
repository = resolve(DatasetRepository)

catalogs = await bus.execute(GetAllCatalogs())
geographical_coverages = await repository.get_geographical_coverage_set()
services = await repository.get_service_set()
technical_sources = await repository.get_technical_source_set()
tags = await bus.execute(GetAllTags())
licenses = await bus.execute(GetLicenseSet())

return DatasetFiltersView(
organization_siret=[catalog.organization for catalog in catalogs],
geographical_coverage=sorted(geographical_coverages),
service=list(services),
format=list(DataFormat),
Expand Down
2 changes: 2 additions & 0 deletions server/application/datasets/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from server.domain.datasets.repositories import DatasetHeadlines

from ..catalog_records.views import CatalogRecordView
from ..organizations.views import OrganizationView
from ..tags.views import TagView


Expand Down Expand Up @@ -39,6 +40,7 @@ class DatasetView(BaseModel):


class DatasetFiltersView(BaseModel):
organization_siret: List[OrganizationView]
geographical_coverage: List[str]
service: List[str]
format: List[DataFormat]
Expand Down
5 changes: 4 additions & 1 deletion server/domain/catalogs/repositories.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Optional

from server.seedwork.domain.repositories import Repository

Expand All @@ -10,5 +10,8 @@ class CatalogRepository(Repository):
async def get_by_siret(self, siret: Siret) -> Optional[Catalog]:
raise NotImplementedError # pragma: no cover

async def get_all(self) -> List[Catalog]:
raise NotImplementedError # pragma: no cover

async def insert(self, catalog: Catalog) -> Siret:
raise NotImplementedError # pragma: no cover
2 changes: 2 additions & 0 deletions server/domain/datasets/specifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
from typing import Optional, Sequence

from server.domain.common.types import ID
from server.domain.organizations.types import Siret

from .entities import DataFormat


@dataclass(frozen=True)
class DatasetSpec:
search_term: Optional[str] = None
organization_siret: Optional[Siret] = None
geographical_coverage__in: Optional[Sequence[str]] = None
service__in: Optional[Sequence[str]] = None
format__in: Optional[Sequence[DataFormat]] = None
Expand Down
Loading

0 comments on commit d694238

Please sign in to comment.