diff --git a/components/ContactPointSelect.vue b/components/ContactPointSelect.vue index b6abc212..de618af1 100644 --- a/components/ContactPointSelect.vue +++ b/components/ContactPointSelect.vue @@ -9,7 +9,6 @@ :display-value="(option) => 'id' in option ? (option.name || option.email || $t('Unknown')) : t('New contact')" :get-option-id="(option) => 'id' in option ? option.id : 'new'" :multiple="false" - required :loading :error-text :warning-text @@ -39,6 +38,7 @@ > () + const props = defineProps<{ organization: Organization errorText?: string | null warningText?: string | null }>() -const contactsUrl = computed(() => `/api/1/organizations/${props.organization.id}/contacts`) +onMounted(() => { + if (contact.value && !('id' in contact.value)) { + contact.value = newContactForm.value + } +}) + +const contactsUrl = computed(() => `/api/1/organizations/${props.organization.id}/contacts/`) const { data: contacts, status } = await useAPI>(contactsUrl, { lazy: true }) const loading = computed(() => status.value === 'pending') const contactsWithNewOption = computed>(() => { diff --git a/components/Dataservices/AdminUpdateDataservicePage.vue b/components/Dataservices/AdminUpdateDataservicePage.vue index fa596462..776cabf9 100644 --- a/components/Dataservices/AdminUpdateDataservicePage.vue +++ b/components/Dataservices/AdminUpdateDataservicePage.vue @@ -85,7 +85,7 @@ import type { Dataservice } from '@datagouv/components' import { RiArchiveLine, RiDeleteBin6Line } from '@remixicon/vue' import BrandedButton from '../BrandedButton/BrandedButton.vue' import DescribeDataservice from '~/components/Dataservices/DescribeDataservice.vue' -import type { ContactPoint, DataserviceForm, LinkToSubject } from '~/types/types' +import type { DataserviceForm, LinkToSubject } from '~/types/types' import { toForm, toApi } from '~/utils/dataservices' const { t } = useI18n() @@ -117,11 +117,14 @@ async function save() { loading.value = true if ( - dataserviceForm.value.contact_point + dataserviceForm.value.contact_points && dataserviceForm.value.owned?.organization - && !('id' in dataserviceForm.value.contact_point) ) { - dataserviceForm.value.contact_point = await newContactPoint($api, dataserviceForm.value.owned?.organization, dataserviceForm.value.contact_point) + for (const contactPointKey in dataserviceForm.value.contact_points) { + if (!('id' in dataserviceForm.value.contact_points[contactPointKey])) { + dataserviceForm.value.contact_points[contactPointKey] = await newContactPoint($api, dataserviceForm.value.owned?.organization, dataserviceForm.value.contact_points[contactPointKey]) + } + } } await $api(`/api/1/dataservices/${dataservice.value.id}/`, { method: 'PATCH', diff --git a/components/Dataservices/DescribeDataservice.vue b/components/Dataservices/DescribeDataservice.vue index 0a57fcca..b2f521ca 100644 --- a/components/Dataservices/DescribeDataservice.vue +++ b/components/Dataservices/DescribeDataservice.vue @@ -88,7 +88,7 @@ v-if="form.owned?.organization" :id="contactPointAccordionId" :title="$t('Define a point of contact')" - :state="accordionState('contact_point')" + :state="accordionState('contact_points')" >

{{ $t("Specify a contact point, such as an email or a link to a form, so users can reach you in case of issues or for questions.") }} @@ -336,10 +336,19 @@ + diff --git a/components/Datasets/AdminUpdateDatasetPage.vue b/components/Datasets/AdminUpdateDatasetPage.vue index 51da3929..da515d73 100644 --- a/components/Datasets/AdminUpdateDatasetPage.vue +++ b/components/Datasets/AdminUpdateDatasetPage.vue @@ -135,11 +135,14 @@ async function save() { try { loading.value = true if ( - datasetForm.value.contact_point + datasetForm.value.contact_points && datasetForm.value.owned?.organization - && !('id' in datasetForm.value.contact_point) ) { - datasetForm.value.contact_point = await newContactPoint($api, datasetForm.value.owned?.organization, datasetForm.value.contact_point) + for (const contactPointKey in datasetForm.value.contact_points) { + if (!('id' in datasetForm.value.contact_points[contactPointKey])) { + datasetForm.value.contact_points[contactPointKey] = await newContactPoint($api, datasetForm.value.owned?.organization, datasetForm.value.contact_points[contactPointKey]) + } + } } await $api(`/api/1/datasets/${dataset.value.id}/`, { diff --git a/components/Datasets/DescribeDataset.vue b/components/Datasets/DescribeDataset.vue index d7cdad78..a198154d 100644 --- a/components/Datasets/DescribeDataset.vue +++ b/components/Datasets/DescribeDataset.vue @@ -102,7 +102,7 @@ v-if="form.owned?.organization" :id="contactPointAccordionId" :title="$t('Define a point of contact')" - :state="accordionState('contact_point')" + :state="accordionState('contact_points')" >

{{ $t("Specify a contact point, such as an email or a link to a form, so users can reach you in case of issues or for questions.") }} @@ -342,10 +342,19 @@ + diff --git a/pages/beta/admin/dataservices/new.vue b/pages/beta/admin/dataservices/new.vue index 645b8d1e..2bf65747 100644 --- a/pages/beta/admin/dataservices/new.vue +++ b/pages/beta/admin/dataservices/new.vue @@ -72,7 +72,6 @@ import Step2AddDatasets from '~/components/Dataservices/New/Step2AddDatasets.vue import Step3CompletePublication from '~/components/Dataservices/New/Step3CompletePublication.vue' import Stepper from '~/components/Stepper/Stepper.vue' import type { - ContactPoint, DataserviceForm, DatasetSuggest, } from '~/types/types' @@ -110,7 +109,7 @@ const dataserviceForm = useState( license: null, private: true, rate_limiting: '', - contact_point: null, + contact_points: [], } as DataserviceForm), ) @@ -147,11 +146,14 @@ async function save() { try { loading.value = true if ( - dataserviceForm.value.contact_point + dataserviceForm.value.contact_points && dataserviceForm.value.owned?.organization - && !('id' in dataserviceForm.value.contact_point) ) { - dataserviceForm.value.contact_point = await newContactPoint($api, dataserviceForm.value.owned?.organization, dataserviceForm.value.contact_point) + for (const contactPointKey in dataserviceForm.value.contact_points) { + if (!('id' in dataserviceForm.value.contact_points[contactPointKey])) { + dataserviceForm.value.contact_points[contactPointKey] = await newContactPoint($api, dataserviceForm.value.owned?.organization, dataserviceForm.value.contact_points[contactPointKey]) + } + } } newDataservice.value = await $api('/api/1/dataservices/', { diff --git a/pages/beta/admin/datasets/new.vue b/pages/beta/admin/datasets/new.vue index 5e1774a7..b0f6e3d9 100644 --- a/pages/beta/admin/datasets/new.vue +++ b/pages/beta/admin/datasets/new.vue @@ -100,6 +100,8 @@ const datasetForm = useState(DATASET_FORM_STATE, () => ({ frequency: null as Frequency | null, spatial_zones: [] as Array, spatial_granularity: null as SpatialGranularity | null, + contact_points: [], + private: true, } as DatasetForm)) const datasetFiles = useState>(DATASET_FILES_STATE, () => []) const newDataset = useState('new-dataset', () => null) @@ -129,11 +131,14 @@ async function save() { try { loading.value = true if ( - datasetForm.value.contact_point + datasetForm.value.contact_points && datasetForm.value.owned?.organization - && !('id' in datasetForm.value.contact_point) ) { - datasetForm.value.contact_point = await newContactPoint($api, datasetForm.value.owned?.organization, datasetForm.value.contact_point) + for (const contactPointKey in datasetForm.value.contact_points) { + if (!('id' in datasetForm.value.contact_points[contactPointKey])) { + datasetForm.value.contact_points[contactPointKey] = await newContactPoint($api, datasetForm.value.owned?.organization, datasetForm.value.contact_points[contactPointKey]) + } + } } newDataset.value = newDataset.value || await $api('/api/1/datasets/', { diff --git a/types/types.d.ts b/types/types.d.ts index 9ec19f42..152adc34 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -127,7 +127,7 @@ export type DatasetForm = { description: string tags: Array license: License | null - contact_point: NewContactPoint | ContactPoint | null + contact_points: Array temporal_coverage: { start: null | string, end: null | string } frequency: Frequency | null spatial_zones: Array @@ -145,7 +145,7 @@ export type NewDatasetForApi = { owner?: string tags: Array license?: string - contact_point?: string | null + contact_points?: Array | null temporal_coverage?: { start: string, end: string } frequency?: string spatial?: { @@ -189,7 +189,7 @@ export type DataserviceForm = { title: string acronym: string description: string - contact_point: NewContactPoint | ContactPoint | null + contact_points: Array is_restricted: boolean has_token: boolean base_api_url: string @@ -210,7 +210,7 @@ export type NewDataserviceForApi = { acronym?: string description: string datasets?: Array - contact_point?: string | null + contact_points?: Array | null is_restricted: boolean has_token: boolean base_api_url: string | null @@ -251,6 +251,7 @@ export type ContactPoint = { name: string contact_form?: string email?: string + role: string } export type NewContactPoint = Omit diff --git a/utils/contacts.ts b/utils/contacts.ts index b07349b3..3f8e09cc 100644 --- a/utils/contacts.ts +++ b/utils/contacts.ts @@ -9,6 +9,7 @@ export async function newContactPoint(api: $Fetch, organization: Organization, c name: contactPoint.name, email: contactPoint.email, contact_form: contactPoint.contact_form, + role: contactPoint.role, organization: organization.id, }), }) diff --git a/utils/dataservices.ts b/utils/dataservices.ts index 5f6715c0..888a1cab 100644 --- a/utils/dataservices.ts +++ b/utils/dataservices.ts @@ -19,7 +19,7 @@ export function toForm(dataservice: Dataservice): DataserviceForm { title: dataservice.title, description: dataservice.description, acronym: dataservice.acronym, - contact_point: dataservice.contact_point as unknown as ContactPoint | null, // TODO the API returns a ContactPoint object. + contact_points: (dataservice.contact_points ?? []) as Array, // TODO the API returns a ContactPoint object. is_restricted: dataservice.is_restricted, has_token: dataservice.has_token, base_api_url: dataservice.base_api_url || '', @@ -33,6 +33,7 @@ export function toForm(dataservice: Dataservice): DataserviceForm { } export function toApi(form: DataserviceForm, overrides: { archived_at?: string | null, datasets?: Array, private?: boolean } = {}): NewDataserviceForApi { + const contactPoints = form.contact_points?.filter(cp => 'id' in cp).map(cp => cp.id) ?? [] return { organization: form.owned?.organization?.id, owner: form.owned?.owner?.id, @@ -42,7 +43,7 @@ export function toApi(form: DataserviceForm, overrides: { archived_at?: string | private: overrides.private, archived_at: overrides.archived_at, datasets: overrides.datasets ? overrides.datasets.map(({ id }) => id) : undefined, - contact_point: form.contact_point && 'id' in form.contact_point ? form.contact_point.id : undefined, + contact_points: form.contact_points && contactPoints.length ? contactPoints : undefined, is_restricted: form.is_restricted, has_token: form.has_token, base_api_url: form.base_api_url || null, diff --git a/utils/datasets.ts b/utils/datasets.ts index e8186a18..cbc456e8 100644 --- a/utils/datasets.ts +++ b/utils/datasets.ts @@ -8,7 +8,7 @@ import Documentation from '~/components/Icons/Documentation.vue' import Image from '~/components/Icons/Image.vue' import Link from '~/components/Icons/Link.vue' import Table from '~/components/Icons/Table.vue' -import type { DatasetForm, NewDatasetFile, NewDatasetForApi, SpatialGranularity, SpatialZone } from '~/types/types' +import type { ContactPoint, DatasetForm, NewDatasetFile, NewDatasetForApi, SpatialGranularity, SpatialZone } from '~/types/types' export function getResourceFormatIcon(format: string): Component | null { switch (format?.trim()?.toLowerCase()) { @@ -108,7 +108,7 @@ export function toForm(dataset: Dataset, licenses: Array, frequencies: acronym: dataset.acronym, tags: dataset.tags?.map(text => ({ text })) || [], license: licenses.find(l => l.id === dataset.license) || null, - contact_point: dataset.contact_point, + contact_points: dataset.contact_points ?? [], frequency: frequencies.find(f => f.id === dataset.frequency) || null, temporal_coverage: dataset.temporal_coverage ? { start: dataset.temporal_coverage.start, end: dataset.temporal_coverage.end } : { start: null, end: null }, // TODO fix this type, the API returns an object not a string spatial_zones: dataset.spatial?.zones?.map(id => zones.find(z => z.id === id)).filter(z => z !== undefined) || [], @@ -118,6 +118,7 @@ export function toForm(dataset: Dataset, licenses: Array, frequencies: } export function toApi(form: DatasetForm, overrides: { private?: boolean, archived?: string | null } = {}): NewDatasetForApi { + const contactPoints = form.contact_points?.filter(cp => 'id' in cp).map(cp => cp.id) ?? [] return { organization: form.owned?.organization?.id, owner: form.owned?.owner?.id, @@ -128,7 +129,7 @@ export function toApi(form: DatasetForm, overrides: { private?: boolean, archive acronym: form.acronym, tags: form.tags.map(t => t.text), license: form.license?.id || '', - contact_point: form.contact_point && 'id' in form.contact_point ? form.contact_point.id : undefined, + contact_points: form.contact_points && contactPoints.length ? contactPoints : undefined, frequency: form.frequency?.id || '', temporal_coverage: (form.temporal_coverage.start && form.temporal_coverage.end) ? form.temporal_coverage as { start: string, end: string } : undefined, spatial: (form.spatial_granularity || form.spatial_zones)