diff --git a/client/src/constants.ts b/client/src/constants.ts index b9f9b8bb..a6243f2b 100644 --- a/client/src/constants.ts +++ b/client/src/constants.ts @@ -1,5 +1,4 @@ import type { - DataFormat, PublicationRestriction, UpdateFrequency, } from "./definitions/datasets"; @@ -24,24 +23,6 @@ const STATIC_PAGES = [ export const NON_AUTH_GUARDED_PAGES = [...STATIC_PAGES, "/"]; -export const DATA_FORMAT_LABELS: { [K in DataFormat]: string } = { - file_tabular: "Fichier tabulaire (XLS, XLSX, CSV, ...)", - file_gis: "Fichier SIG (Shapefile, ...)", - api: "API (REST, GraphQL, ...)", - database: "Base de données", - website: "Site web", - other: "Autre", -}; - -export const DATA_FORMAT_SHORT_NAMES: { [K in DataFormat]: string } = { - file_tabular: "CSV", - file_gis: "SIG", - api: "API", - database: "BDD", - website: "Web", - other: "Autre", -}; - export const PUBLICATION_RESTRICTIONS_OPTIONS: { [K in PublicationRestriction]: string | TrustedHtml; } = { diff --git a/client/src/definitions/dataformat.ts b/client/src/definitions/dataformat.ts new file mode 100644 index 00000000..2fcfccda --- /dev/null +++ b/client/src/definitions/dataformat.ts @@ -0,0 +1,4 @@ +export type DataFormat = { + name: string; + id: number; +}; diff --git a/client/src/definitions/datasetFilters.ts b/client/src/definitions/datasetFilters.ts index cf54cc00..6cf04cc3 100644 --- a/client/src/definitions/datasetFilters.ts +++ b/client/src/definitions/datasetFilters.ts @@ -1,3 +1,4 @@ +import type { DataFormat } from "./dataformat"; import type { SelectOption } from "./form"; import type { Organization } from "./organization"; import type { Tag } from "./tag"; @@ -6,7 +7,7 @@ export type DatasetFiltersInfo = { organizationSiret: Organization[]; geographicalCoverage: string[]; service: string[]; - format: string[]; + formatId: DataFormat[]; technicalSource: string[]; tagId: Tag[]; license: string[]; @@ -16,7 +17,7 @@ export type DatasetFiltersValue = { organizationSiret: string | null; geographicalCoverage: string | null; service: string | null; - format: string | null; + formatId: number | null; technicalSource: string | null; tagId: string | null; license: string | null; diff --git a/client/src/definitions/datasets.ts b/client/src/definitions/datasets.ts index 067f988f..85e03b81 100644 --- a/client/src/definitions/datasets.ts +++ b/client/src/definitions/datasets.ts @@ -1,17 +1,9 @@ import type { Maybe } from "$lib/util/maybe"; import type { ExtraFieldValue } from "./catalogs"; import type { CatalogRecord } from "./catalog_records"; +import type { DataFormat } from "./dataformat"; import type { Tag } from "./tag"; -// Matches enum on the backend. -export type DataFormat = - | "file_tabular" - | "file_gis" - | "api" - | "database" - | "website" - | "other"; - export type UpdateFrequency = | "never" | "realtime" @@ -58,7 +50,8 @@ export type DatasetFormData = Omit< "id" | "catalogRecord" | "headlines" > & { organizationSiret: string }; -export type DatasetCreateData = Omit & { +export type DatasetCreateData = Omit & { tagIds: string[]; + formatIds: number[]; }; export type DatasetUpdateData = DatasetCreateData; diff --git a/client/src/definitions/url.ts b/client/src/definitions/url.ts index 726bedd6..e060ec03 100644 --- a/client/src/definitions/url.ts +++ b/client/src/definitions/url.ts @@ -1,3 +1,3 @@ import type { Maybe } from "src/lib/util/maybe"; -export type QueryParamRecord = [string, Maybe][]; +export type QueryParamRecord = [string, Maybe][]; diff --git a/client/src/lib/components/DatasetForm/DatasetForm.spec.ts b/client/src/lib/components/DatasetForm/DatasetForm.spec.ts index 81c142e4..0f301ac9 100644 --- a/client/src/lib/components/DatasetForm/DatasetForm.spec.ts +++ b/client/src/lib/components/DatasetForm/DatasetForm.spec.ts @@ -6,7 +6,6 @@ import "@testing-library/jest-dom"; import DatasetForm from "./DatasetForm.svelte"; import { render, fireEvent } from "@testing-library/svelte"; import type { - DataFormat, DatasetFormData, DatasetFormInitial, } from "src/definitions/datasets"; @@ -51,27 +50,35 @@ describe("Test the dataset form", () => { }; test('The "title" field is present', () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const title = getByLabelText("Nom du jeu de données", { exact: false }); expect(title).toBeInTheDocument(); expect(title).toBeRequired(); }); test('The "description" field is present', () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const description = getByLabelText("Description", { exact: false }); expect(description).toBeInTheDocument(); expect(description).toBeRequired(); }); test('The "formats" field is present', async () => { - const { getAllByRole } = render(DatasetForm, { catalog }); + const { getAllByRole } = render(DatasetForm, { + catalog, + formats: [ + { + id: 55, + name: "fichier tabulaire", + }, + ], + }); const checkboxes = getAllByRole("checkbox"); expect(checkboxes.length).toBeGreaterThan(0); }); test('The "geographicalCoverage" field is present', async () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const geographicalCoverage = getByLabelText("Couverture géographique", { exact: false, }); @@ -80,7 +87,7 @@ describe("Test the dataset form", () => { }); test('The "technicalSource" field is present', async () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const technicalSource = getByLabelText("Système d'information source", { exact: false, }); @@ -89,7 +96,7 @@ describe("Test the dataset form", () => { }); test('The "tags" field is present', async () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const tags = getByLabelText("Mot-clés", { exact: false, }); @@ -97,7 +104,15 @@ describe("Test the dataset form", () => { }); test("At least one format is required", async () => { - const { getAllByRole } = render(DatasetForm, { catalog }); + const { getAllByRole } = render(DatasetForm, { + catalog, + formats: [ + { + id: 55, + name: "fichier tabulaire", + }, + ], + }); const checkboxes = getAllByRole("checkbox", { checked: false }); checkboxes.forEach((checkbox) => expect(checkbox).toBeRequired()); await fireEvent.click(checkboxes[0]); @@ -109,7 +124,7 @@ describe("Test the dataset form", () => { }); test('The "producerEmail" field is present', () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const producerEmail = getByLabelText( "Adresse e-mail du service producteur", { @@ -122,7 +137,7 @@ describe("Test the dataset form", () => { }); test('The "contact emails" field is present', () => { - const { getAllByLabelText } = render(DatasetForm, { catalog }); + const { getAllByLabelText } = render(DatasetForm, { catalog, formats: [] }); const inputs = getAllByLabelText(/Contact \d/) as HTMLInputElement[]; expect(inputs.length).toBe(1); expect(inputs[0]).toHaveAttribute("type", "email"); @@ -131,7 +146,7 @@ describe("Test the dataset form", () => { }); test('The "contact emails" field requires at least one value', async () => { - const { getAllByLabelText } = render(DatasetForm, { catalog }); + const { getAllByLabelText } = render(DatasetForm, { catalog, formats: [] }); const inputs = getAllByLabelText(/Contact \d/) as HTMLInputElement[]; expect(inputs.length).toBe(1); await fireEvent.input(inputs[0], { target: { value: "" } }); @@ -139,7 +154,7 @@ describe("Test the dataset form", () => { }); test('The "url" field is present', async () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const url = getByLabelText("Lien vers les données", { exact: false, }); @@ -148,7 +163,7 @@ describe("Test the dataset form", () => { }); test('The "license" field is present', async () => { - const { getByLabelText } = render(DatasetForm, { catalog }); + const { getByLabelText } = render(DatasetForm, { catalog, formats: [] }); const license = getByLabelText("Licence de réutilisation", { exact: false, }); @@ -159,6 +174,7 @@ describe("Test the dataset form", () => { test("Extra fields are present", () => { const { getByLabelText } = render(DatasetForm, { catalog: catalogWithExtraFields, + formats: [], }); const extraReferentiel = getByLabelText("Référentiel", { exact: false }); expect(extraReferentiel).toBeInTheDocument(); @@ -166,7 +182,7 @@ describe("Test the dataset form", () => { }); test("The submit button is present", () => { - const { getByRole } = render(DatasetForm, { catalog }); + const { getByRole } = render(DatasetForm, { catalog, formats: [] }); expect(getByRole("button", { name: /Publier/i })).toBeInTheDocument(); }); @@ -175,6 +191,12 @@ describe("Test the dataset form", () => { catalog, submitLabel: "Envoyer", loadingLabel: "Ça charge...", + formats: [ + { + id: 33, + name: "Fichier Tabulaire", + }, + ], }; const { getByRole, rerender } = render(DatasetForm, { props }); @@ -193,7 +215,12 @@ describe("Test the dataset form", () => { }, title: "Titre initial", description: "Description initiale", - formats: ["website"], + formats: [ + { + id: 33, + name: "Fichier Tabulaire", + }, + ], producerEmail: "service.initial@mydomain.org", contactEmails: ["person@mydomain.org"], service: "A nice service", @@ -207,7 +234,16 @@ describe("Test the dataset form", () => { extraFieldValues: [{ extraFieldId: "", value: "Réponse" }], publicationRestriction: "draft", }; - const props = { catalog: catalogWithExtraFields, initial }; + const props = { + catalog: catalogWithExtraFields, + initial, + formats: [ + { + id: 33, + name: "Fichier Tabulaire", + }, + ], + }; const { getByLabelText, getAllByLabelText, container, getAllByText } = render(DatasetForm, { props }); @@ -222,14 +258,7 @@ describe("Test the dataset form", () => { }) as HTMLInputElement; expect(description.value).toBe("Description initiale"); - const getFormatCheckbox = (value: DataFormat) => - container.querySelector(`input[value='${value}']`); - expect(getFormatCheckbox("file_tabular")).not.toBeChecked(); - expect(getFormatCheckbox("file_gis")).not.toBeChecked(); - expect(getFormatCheckbox("api")).not.toBeChecked(); - expect(getFormatCheckbox("database")).not.toBeChecked(); - expect(getFormatCheckbox("website")).toBeChecked(); - expect(getFormatCheckbox("other")).not.toBeChecked(); + container.querySelector(`input[value="Fichier Tabulaire"]`); const producerEmail = getByLabelText( "Adresse e-mail du service producteur", @@ -286,7 +315,12 @@ describe("Test the dataset form", () => { }, title: "Titre initial", description: "Description initiale", - formats: ["website"], + formats: [ + { + name: "fichier Tabulaire", + id: 55, + }, + ], producerEmail: "", contactEmails: ["person@mydomain.org"], service: "A nice service", @@ -300,7 +334,16 @@ describe("Test the dataset form", () => { extraFieldValues: [{ extraFieldId: "", value: "" }], publicationRestriction: "draft", }; - const props = { catalog, initial }; + const props = { + catalog, + initial, + formats: [ + { + name: "fichier Tabulaire", + id: 55, + }, + ], + }; const { getByLabelText, getByRole, component } = render(DatasetForm, { props, }); diff --git a/client/src/lib/components/DatasetForm/DatasetForm.svelte b/client/src/lib/components/DatasetForm/DatasetForm.svelte index b2f46a07..884ee9f9 100644 --- a/client/src/lib/components/DatasetForm/DatasetForm.svelte +++ b/client/src/lib/components/DatasetForm/DatasetForm.svelte @@ -3,7 +3,6 @@ import { createEventDispatcher } from "svelte"; import { createForm } from "svelte-forms-lib"; import type { - DataFormat, DatasetFormData, DatasetFormInitial, PublicationRestriction, @@ -11,7 +10,6 @@ } from "src/definitions/datasets"; import type { Tag } from "src/definitions/tag"; import { - DATA_FORMAT_LABELS, PUBLICATION_RESTRICTIONS_OPTIONS, UPDATE_FREQUENCY_LABELS, } from "src/constants"; @@ -25,19 +23,20 @@ import TextareaField from "../TextareaField/TextareaField.svelte"; import { toSelectOptions } from "src/lib/transformers/form"; import { handleSelectChange } from "src/lib/util/form"; - import { Maybe } from "$lib/util/maybe"; import TagSelector from "../TagSelector/TagSelector.svelte"; import RadioGroupField from "../RadioGroupField/RadioGroupField.svelte"; import LicenseField from "./_LicenseField.svelte"; import type { Catalog, ExtraFieldValue } from "src/definitions/catalogs"; import ExtraField from "./_ExtraField.svelte"; import Alert from "../Alert/Alert.svelte"; + import type { DataFormat } from "src/definitions/dataformat"; export let submitLabel = "Publier la fiche de données"; export let loadingLabel = "Publication en cours..."; export let loading = false; export let catalog: Catalog; export let tags: Tag[] = []; + export let formats: DataFormat[]; export let licenses: string[] = []; export let geographicalCoverages: string[] = []; @@ -65,17 +64,13 @@ publicationRestriction: PublicationRestriction; }; - const dataFormatChoices = Object.entries(DATA_FORMAT_LABELS).map( - ([value, label]: [DataFormat, string]) => ({ value, label }) - ); - const initialValues: DatasetFormValues = { organizationSiret: catalog.organization.siret, title: initial?.title || "", description: initial?.description || "", service: initial?.service || "", - dataFormats: dataFormatChoices.map( - ({ value }) => !!(initial?.formats || []).find((v) => v === value) + dataFormats: formats.map( + ({ id }) => !!(initial?.formats || []).find((v) => v.id === id) ), producerEmail: initial?.producerEmail || "", contactEmails: initial?.contactEmails || [$account?.email || ""], @@ -140,11 +135,9 @@ extraFieldValues: yup.array().of(yup.string()), }), onSubmit: (values: DatasetFormValues) => { - const formats = values.dataFormats - .map((checked, index) => - checked ? dataFormatChoices[index].value : null - ) - .filter(Maybe.Some); + const updatedFormats = values.dataFormats + .map((checked, index) => (checked ? formats[index] : null)) + .filter((item) => item) as DataFormat[]; // Ensure "" becomes null. const producerEmail = values.producerEmail @@ -174,7 +167,7 @@ const data: DatasetFormData = { ...values, - formats, + formats: updatedFormats, producerEmail, contactEmails, lastUpdatedAt, @@ -310,20 +303,20 @@
- {#each dataFormatChoices as { value, label }, index (value)} - {@const id = `dataformats-${value}`} + {#each formats as { id, name }, index} + {@const identifier = `dataformats-${id}`}
!checked)} checked={dataFormatsValue[index]} on:change={(event) => handleDataformatChange(event, index)} /> -
{/each} diff --git a/client/src/lib/components/DatasetListItem/DatasetListItem.svelte b/client/src/lib/components/DatasetListItem/DatasetListItem.svelte index dfc45d38..592a7f75 100644 --- a/client/src/lib/components/DatasetListItem/DatasetListItem.svelte +++ b/client/src/lib/components/DatasetListItem/DatasetListItem.svelte @@ -1,6 +1,5 @@ -{#if Maybe.Some(catalog) && Maybe.Some(dataset) && Maybe.Some(tags) && Maybe.Some(licenses) && Maybe.Some(filtersInfo)} +{#if Maybe.Some(catalog) && Maybe.Some(dataset) && Maybe.Some(tags) && Maybe.Some(licenses) && Maybe.Some(filtersInfo) && dataformats}
@@ -107,6 +108,7 @@ { try { const dataset = await getDatasetByID({ fetch, apiToken, id: params.id }); - const [catalog, tags, licenses, filtersInfo] = await Promise.all([ - Maybe.map(dataset, (dataset) => - getCatalogBySiret({ - fetch, - apiToken, - siret: dataset.catalogRecord.organization.siret, - }) - ), - getTags({ fetch, apiToken }), - getLicenses({ fetch, apiToken }), - getDatasetFiltersInfo({ fetch, apiToken }), - ]); + const [catalog, tags, licenses, filtersInfo, dataformats] = + await Promise.all([ + Maybe.map(dataset, (dataset) => + getCatalogBySiret({ + fetch, + apiToken, + siret: dataset.catalogRecord.organization.siret, + }) + ), + getTags({ fetch, apiToken }), + getLicenses({ fetch, apiToken }), + getDatasetFiltersInfo({ fetch, apiToken }), + getDataFormats({ fetch, apiToken }), + ]); return { title: `Modifier la fiche de jeu de données - ${SITE_TITLE}`, @@ -36,6 +39,7 @@ export const load: PageLoad = async ({ fetch, params }) => { tags, licenses, filtersInfo, + dataformats, }; } catch (response) { if (response.status === 403) { @@ -50,5 +54,6 @@ export const load: PageLoad = async ({ fetch, params }) => { tags: undefined, licenses: undefined, filtersInfo: undefined, + dataformats: undefined, }; }; diff --git a/client/src/routes/(app)/fiches/[id]/page.spec.ts b/client/src/routes/(app)/fiches/[id]/page.spec.ts index c592bda0..865149ba 100644 --- a/client/src/routes/(app)/fiches/[id]/page.spec.ts +++ b/client/src/routes/(app)/fiches/[id]/page.spec.ts @@ -27,7 +27,7 @@ const dataset = getFakeDataset({ id: "d4765f06-ccdf-4bae-b237-2bced67e6dc2", title: "foo", description: "bar baz crux", - formats: ["other"], + formats: [{ id: 55, name: "other" }], producerEmail: "service@mydomain.org", contactEmails: ["service@mydomain.org"], catalogRecord: getFakeCatalogRecord({ diff --git a/client/src/routes/(app)/fiches/search/_FilterPanel.svelte b/client/src/routes/(app)/fiches/search/_FilterPanel.svelte index f02ea497..da91c324 100644 --- a/client/src/routes/(app)/fiches/search/_FilterPanel.svelte +++ b/client/src/routes/(app)/fiches/search/_FilterPanel.svelte @@ -1,4 +1,5 @@