@datagouv/components-next 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +1 -1
  2. package/assets/main.css +56 -1
  3. package/dist/Control-BNCDn-8E.js +148 -0
  4. package/dist/{Datafair.client-x39O4yfF.js → Datafair.client-Dls5AHTE.js} +1 -1
  5. package/dist/Event-BOgJUhNR.js +738 -0
  6. package/dist/Image-BN-4XkIn.js +247 -0
  7. package/dist/{JsonPreview.client-BMsC5JcY.js → JsonPreview.client-DPDTs433.js} +14 -14
  8. package/dist/Map-BdT3i2C4.js +7609 -0
  9. package/dist/MapContainer.client-BdAzd7bj.js +105 -0
  10. package/dist/OSM-CamriM9b.js +71 -0
  11. package/dist/{PdfPreview.client-COOkEkRA.js → PdfPreview.client-CopqSDyt.js} +3 -3
  12. package/dist/{Pmtiles.client-BaiIo4VZ.js → Pmtiles.client-mF6xaOO_.js} +2 -2
  13. package/dist/ScaleLine-BiesrgOv.js +165 -0
  14. package/dist/Swagger.client-eJ7gpfZA.js +4 -0
  15. package/dist/Tile-DCuqwNOI.js +1206 -0
  16. package/dist/TileImage-CmZf8EdU.js +1067 -0
  17. package/dist/View-DcDc7N2K.js +2858 -0
  18. package/dist/{XmlPreview.client-CAdN0w_Y.js → XmlPreview.client-C0OgBkSq.js} +7 -7
  19. package/dist/common-C4rDcQpp.js +243 -0
  20. package/dist/components-next.css +1 -1
  21. package/dist/components-next.js +153 -117
  22. package/dist/components.css +1 -1
  23. package/dist/{MapContainer.client-DeSo8EvG.js → index-BRGqW8aQ.js} +4975 -21416
  24. package/dist/leaflet-src-7m1mB8LI.js +6338 -0
  25. package/dist/{main-Dgri3TQL.js → main-CNHxAJ8J.js} +56758 -51450
  26. package/dist/proj-CKwYjU38.js +1569 -0
  27. package/dist/tilecoord-YW3qEH_j.js +884 -0
  28. package/dist/{vue3-xml-viewer.common-D6skc_Ai.js → vue3-xml-viewer.common-CmAdQfIy.js} +1 -1
  29. package/package.json +5 -1
  30. package/src/components/ActivityList/ActivityList.vue +6 -2
  31. package/src/components/AppLink.vue +4 -1
  32. package/src/components/Avatar.vue +2 -2
  33. package/src/components/AvatarWithName.vue +8 -4
  34. package/src/components/BouncingDots.vue +21 -0
  35. package/src/components/BrandedButton.vue +2 -0
  36. package/src/components/CopyButton.vue +19 -7
  37. package/src/components/DataserviceCard.vue +83 -118
  38. package/src/components/DatasetCard.vue +110 -171
  39. package/src/components/DatasetInformation/DatasetEmbedSection.vue +43 -0
  40. package/src/components/DatasetInformation/DatasetInformationSection.vue +73 -0
  41. package/src/components/DatasetInformation/DatasetSchemaSection.vue +74 -0
  42. package/src/components/DatasetInformation/DatasetSpatialSection.vue +59 -0
  43. package/src/components/DatasetInformation/DatasetTemporalitySection.vue +45 -0
  44. package/src/components/DatasetInformation/index.ts +5 -0
  45. package/src/components/DatasetQualityTooltipContent.vue +3 -3
  46. package/src/components/DescriptionList.vue +1 -4
  47. package/src/components/DescriptionListDetails.vue +5 -0
  48. package/src/components/DescriptionListTerm.vue +5 -0
  49. package/src/components/DiscussionMessageCard.vue +63 -0
  50. package/src/components/ExtraAccordion.vue +4 -4
  51. package/src/components/Form/BadgeSelect.vue +35 -0
  52. package/src/components/Form/FormatSelect.vue +28 -0
  53. package/src/components/Form/GeozoneSelect.vue +52 -0
  54. package/src/components/Form/GranularitySelect.vue +29 -0
  55. package/src/components/Form/LicenseSelect.vue +30 -0
  56. package/src/components/Form/OrganizationSelect.vue +62 -0
  57. package/src/components/Form/OrganizationTypeSelect.vue +34 -0
  58. package/src/components/Form/ReuseTopicSelect.vue +29 -0
  59. package/src/components/Form/SchemaSelect.vue +30 -0
  60. package/src/components/Form/SearchableSelect.vue +334 -0
  61. package/src/components/Form/SelectGroup.vue +132 -0
  62. package/src/components/Form/TagSelect.vue +38 -0
  63. package/src/components/LeafletMap.vue +31 -0
  64. package/src/components/LicenseBadge.vue +24 -0
  65. package/src/components/LoadingBlock.vue +23 -2
  66. package/src/components/MarkdownViewer.vue +3 -1
  67. package/src/components/ObjectCard.vue +42 -0
  68. package/src/components/ObjectCardBadge.vue +22 -0
  69. package/src/components/ObjectCardHeader.vue +35 -0
  70. package/src/components/ObjectCardOwner.vue +43 -0
  71. package/src/components/ObjectCardShortDescription.vue +28 -0
  72. package/src/components/OrganizationCard.vue +35 -20
  73. package/src/components/OrganizationLogo.vue +1 -1
  74. package/src/components/OrganizationNameWithCertificate.vue +13 -7
  75. package/src/components/OwnerTypeIcon.vue +1 -0
  76. package/src/components/Pagination.vue +1 -1
  77. package/src/components/Placeholder.vue +5 -2
  78. package/src/components/PostCard.vue +62 -0
  79. package/src/components/RadioGroup.vue +32 -0
  80. package/src/components/RadioInput.vue +64 -0
  81. package/src/components/ResourceAccordion/EditButton.vue +2 -3
  82. package/src/components/ResourceAccordion/MapContainer.client.vue +20 -16
  83. package/src/components/ResourceAccordion/Metadata.vue +11 -24
  84. package/src/components/ResourceAccordion/Pmtiles.client.vue +1 -1
  85. package/src/components/ResourceAccordion/Preview.vue +1 -1
  86. package/src/components/ResourceAccordion/ResourceAccordion.vue +30 -20
  87. package/src/components/ResourceAccordion/ResourceIcon.vue +1 -0
  88. package/src/components/ResourceAccordion/SchemaBadge.vue +2 -2
  89. package/src/components/ResourceExplorer/ResourceExplorer.vue +243 -0
  90. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +116 -0
  91. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +361 -0
  92. package/src/components/ReuseCard.vue +8 -28
  93. package/src/components/ReuseHorizontalCard.vue +80 -0
  94. package/src/components/Search/BasicAndAdvancedFilters.vue +49 -0
  95. package/src/components/Search/Filter/AccessTypeFilter.vue +37 -0
  96. package/src/components/Search/Filter/DatasetBadgeFilter.vue +40 -0
  97. package/src/components/Search/Filter/FilterButtonGroup.vue +78 -0
  98. package/src/components/Search/Filter/FormatFamilyFilter.vue +39 -0
  99. package/src/components/Search/Filter/LastUpdateRangeFilter.vue +37 -0
  100. package/src/components/Search/Filter/ProducerTypeFilter.vue +39 -0
  101. package/src/components/Search/Filter/ReuseTypeFilter.vue +42 -0
  102. package/src/components/Search/GlobalSearch.vue +611 -0
  103. package/src/components/Search/SearchInput.vue +63 -0
  104. package/src/components/Search/Sidemenu.vue +38 -0
  105. package/src/components/StatBox.vue +5 -5
  106. package/src/components/Tag.vue +30 -0
  107. package/src/components/Toggletip.vue +6 -2
  108. package/src/components/Tooltip.vue +2 -3
  109. package/src/components/TopicCard.vue +134 -0
  110. package/src/components/radioGroupContext.ts +9 -0
  111. package/src/composables/useDebouncedRef.ts +31 -0
  112. package/src/composables/useMetrics.ts +4 -3
  113. package/src/composables/useResourceCapabilities.ts +118 -0
  114. package/src/composables/useRouteQueryBoolean.ts +10 -0
  115. package/src/composables/useSelectModelSync.ts +89 -0
  116. package/src/composables/useStableQueryParams.ts +84 -0
  117. package/src/config.ts +4 -0
  118. package/src/functions/api.ts +17 -6
  119. package/src/functions/api.types.ts +4 -2
  120. package/src/functions/datasets.ts +1 -29
  121. package/src/functions/description.ts +33 -0
  122. package/src/functions/helpers.ts +11 -0
  123. package/src/functions/markdown.ts +60 -16
  124. package/src/functions/metrics.ts +33 -0
  125. package/src/functions/organizations.ts +5 -5
  126. package/src/main.ts +89 -7
  127. package/src/types/dataservices.ts +14 -12
  128. package/src/types/datasets.ts +20 -7
  129. package/src/types/discussions.ts +20 -0
  130. package/src/types/licenses.ts +3 -3
  131. package/src/types/organizations.ts +13 -1
  132. package/src/types/owned.ts +4 -2
  133. package/src/types/pages.ts +70 -0
  134. package/src/types/posts.ts +27 -0
  135. package/src/types/resources.ts +6 -0
  136. package/src/types/reuses.ts +14 -5
  137. package/src/types/search.ts +379 -0
  138. package/src/types/users.ts +12 -3
  139. package/dist/Swagger.client-CpLgaLg6.js +0 -4
  140. package/src/components/DatasetInformationPanel.vue +0 -211
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <ObjectCard>
3
+ <ObjectCardHeader
4
+ :icon="RiChat3Line"
5
+ :url="discussionUrl || discussion.self_web_url || '#'"
6
+ >
7
+ {{ discussion.title }}
8
+ </ObjectCardHeader>
9
+
10
+ <div
11
+ v-if="discussion.organization || discussion.user"
12
+ class="text-sm m-0 flex flex-wrap md:flex-nowrap gap-y-1 items-center truncate"
13
+ >
14
+ <ObjectCardOwner
15
+ :organization="discussion.organization"
16
+ :owner="discussion.user"
17
+ :organization-url="organizationUrl"
18
+ />
19
+ <RiSubtractLine
20
+ aria-hidden="true"
21
+ class="size-4 flex-none fill-gray-medium"
22
+ />
23
+ <span class="text-gray-medium whitespace-nowrap">
24
+ {{ t('Posté {date}', { date: formatDate(discussion.created) }) }}
25
+ </span>
26
+ </div>
27
+
28
+ <ObjectCardShortDescription :text="firstMessageContent" />
29
+
30
+ <slot />
31
+ </ObjectCard>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { RiChat3Line, RiSubtractLine } from '@remixicon/vue'
36
+ import { computed } from 'vue'
37
+ import type { RouteLocationRaw } from 'vue-router'
38
+ import { useFormatDate } from '../functions/dates'
39
+ import { useTranslation } from '../composables/useTranslation'
40
+ import type { Thread } from '../types/discussions'
41
+ import ObjectCard from './ObjectCard.vue'
42
+ import ObjectCardHeader from './ObjectCardHeader.vue'
43
+ import ObjectCardOwner from './ObjectCardOwner.vue'
44
+ import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
45
+
46
+ const props = defineProps<{
47
+ discussion: Thread
48
+ discussionUrl?: RouteLocationRaw
49
+ organizationUrl?: RouteLocationRaw
50
+ }>()
51
+
52
+ const { t } = useTranslation()
53
+ const { formatRelativeIfRecentDate } = useFormatDate()
54
+
55
+ const firstMessageContent = computed(() => props.discussion.discussion?.[0]?.content)
56
+
57
+ const formatDate = (dateString: string) => {
58
+ return formatRelativeIfRecentDate(dateString, {
59
+ dateStyle: 'long',
60
+ timeStyle: 'short',
61
+ })
62
+ }
63
+ </script>
@@ -4,12 +4,12 @@
4
4
  as="div"
5
5
  >
6
6
  <header
7
- class="flex flex-wrap items-center pb-6 mb-6 border-bottom border-gray-default"
7
+ class="flex flex-wrap items-center pb-6 mb-6 border-b border-gray-default"
8
8
  >
9
9
  <div class="fr-col">
10
10
  <component
11
11
  :is="titleLevel"
12
- class="subtitle subtitle--uppercase fr-m-0"
12
+ class="subtitle uppercase m-0"
13
13
  >
14
14
  {{ titleText }}
15
15
  </component>
@@ -34,7 +34,7 @@
34
34
  </div>
35
35
  </header>
36
36
  <DisclosurePanel :id="accordionId">
37
- <div class="pb-6 mb-6 border-bottom border-gray-default">
37
+ <div class="pb-6 mb-6 border-b border-gray-default">
38
38
  <div
39
39
  class="fr-grid-row fr-grid-row--gutters fr-text--sm fr-m-0"
40
40
  data-testid="extra-list"
@@ -44,7 +44,7 @@
44
44
  :key="key"
45
45
  class="fr-col-12 fr-col-sm-6 fr-col-md-4"
46
46
  >
47
- <h3 class="subtitle fr-mb-1v">
47
+ <h3 class="subtitle mb-1">
48
48
  {{ key }}
49
49
  </h3>
50
50
  <p class="text-sm m-0 text-gray-medium break-all">
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="badges"
5
+ :loading="status === 'pending'"
6
+ :label="t('Label de données')"
7
+ :placeholder="t('Tous les labels')"
8
+ :get-option-id="(b: TranslatedBadge) => b.kind"
9
+ :display-value="(b: TranslatedBadge) => b.label"
10
+ :multiple="false"
11
+ />
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { computed } from 'vue'
16
+ import { useTranslation } from '../../composables/useTranslation'
17
+ import { useSelectModelSync } from '../../composables/useSelectModelSync'
18
+ import { useFetch } from '../../functions/api'
19
+ import type { TranslatedBadge } from '../../types/badges'
20
+ import SearchableSelect from './SearchableSelect.vue'
21
+
22
+ const model = defineModel<TranslatedBadge | null>({ default: null })
23
+ const id = defineModel<string | undefined>('id')
24
+
25
+ const { t } = useTranslation()
26
+
27
+ const { data: badgesRecord, status } = await useFetch<Record<string, string>>('/api/1/datasets/badges/', { lazy: true })
28
+
29
+ const badges = computed<TranslatedBadge[]>(() => {
30
+ if (!badgesRecord.value) return []
31
+ return Object.entries(badgesRecord.value).map(([kind, label]) => ({ kind, label }))
32
+ })
33
+
34
+ useSelectModelSync({ model, id, items: badges, getId: b => b.kind })
35
+ </script>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="formats ?? []"
5
+ :loading="status === 'pending'"
6
+ :label="t('Formats')"
7
+ :placeholder="t('Tous les formats')"
8
+ :get-option-id="(f: string) => f"
9
+ :display-value="(f: string) => f"
10
+ :multiple="false"
11
+ />
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { useTranslation } from '../../composables/useTranslation'
16
+ import { useStringSelectSync } from '../../composables/useSelectModelSync'
17
+ import { useFetch } from '../../functions/api'
18
+ import SearchableSelect from './SearchableSelect.vue'
19
+
20
+ const model = defineModel<string | null>({ default: null })
21
+ const id = defineModel<string | undefined>('id')
22
+
23
+ const { t } = useTranslation()
24
+
25
+ const { data: formats, status } = await useFetch<string[]>('/api/1/datasets/extensions/', { lazy: true })
26
+
27
+ useStringSelectSync({ model, id })
28
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="[]"
5
+ :suggest="suggestGeozones"
6
+ :label="t('Couverture spatiale')"
7
+ :placeholder="t('Toutes les couvertures')"
8
+ :get-option-id="(g: SpatialZone) => g.id"
9
+ :display-value="(g: SpatialZone) => g.name"
10
+ :multiple="false"
11
+ :loading="fetching"
12
+ >
13
+ <template #option="{ option }">
14
+ <div class="flex-1">
15
+ {{ option.name }}
16
+ </div>
17
+ <code class="bg-gray-100 text-gray-600 p-1 text-xs rounded">{{ option.code }}</code>
18
+ </template>
19
+ </SearchableSelect>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { ofetch } from 'ofetch'
24
+ import { useComponentsConfig } from '../../config'
25
+ import { useTranslation } from '../../composables/useTranslation'
26
+ import { useAsyncSelectModelSync } from '../../composables/useSelectModelSync'
27
+ import type { SpatialZone } from '../../types/granularity'
28
+ import SearchableSelect from './SearchableSelect.vue'
29
+
30
+ const model = defineModel<SpatialZone | null>({ default: null })
31
+ const id = defineModel<string | undefined>('id')
32
+
33
+ const config = useComponentsConfig()
34
+ const { t } = useTranslation()
35
+
36
+ const { fetching } = useAsyncSelectModelSync({
37
+ model,
38
+ id,
39
+ getId: z => z.id,
40
+ fetchById: async (zoneId) => {
41
+ const zones = await suggestGeozones(zoneId)
42
+ return zones.find(z => z.id === zoneId) ?? null
43
+ },
44
+ })
45
+
46
+ async function suggestGeozones(q: string) {
47
+ return await ofetch<SpatialZone[]>('/api/1/spatial/zones/suggest/', {
48
+ baseURL: config.apiBase,
49
+ query: { q, size: 20 },
50
+ })
51
+ }
52
+ </script>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="granularities ?? []"
5
+ :loading="status === 'pending'"
6
+ :label="t('Granularité spatiale')"
7
+ :placeholder="t('Toutes les granularités')"
8
+ :get-option-id="(g: Granularity) => g.id"
9
+ :display-value="(g: Granularity) => g.name"
10
+ :multiple="false"
11
+ />
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { useTranslation } from '../../composables/useTranslation'
16
+ import { useSelectModelSync } from '../../composables/useSelectModelSync'
17
+ import { useFetch } from '../../functions/api'
18
+ import type { Granularity } from '../../types/granularity'
19
+ import SearchableSelect from './SearchableSelect.vue'
20
+
21
+ const model = defineModel<Granularity | null>({ default: null })
22
+ const id = defineModel<string | undefined>('id')
23
+
24
+ const { t } = useTranslation()
25
+
26
+ const { data: granularities, status } = await useFetch<Granularity[]>('/api/1/spatial/granularities/', { lazy: true })
27
+
28
+ useSelectModelSync({ model, id, items: granularities, getId: g => g.id })
29
+ </script>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="licenses ?? []"
5
+ :loading="status === 'pending'"
6
+ :label="t('Licences')"
7
+ :explanation="t('Les licences définissent les règles de réutilisation des jeux de données publiés.')"
8
+ :placeholder="t('Toutes les licences')"
9
+ :get-option-id="(l: License) => l.id"
10
+ :display-value="(l: License) => l.title"
11
+ :multiple="false"
12
+ />
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { useTranslation } from '../../composables/useTranslation'
17
+ import { useSelectModelSync } from '../../composables/useSelectModelSync'
18
+ import { useFetch } from '../../functions/api'
19
+ import type { License } from '../../types/licenses'
20
+ import SearchableSelect from './SearchableSelect.vue'
21
+
22
+ const model = defineModel<License | null>({ default: null })
23
+ const id = defineModel<string | undefined>('id')
24
+
25
+ const { t } = useTranslation()
26
+
27
+ const { data: licenses, status } = await useFetch<License[]>('/api/1/datasets/licenses/', { lazy: true })
28
+
29
+ useSelectModelSync({ model, id, items: licenses, getId: l => l.id })
30
+ </script>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="[]"
5
+ :suggest="suggestOrganizations"
6
+ :label="t('Organisations')"
7
+ :placeholder="t('Toutes les organisations')"
8
+ :get-option-id="(option) => option.id"
9
+ :display-value="(option) => option.name"
10
+ :filter="(option, query) => (option.name).toLocaleLowerCase().includes(query.toLocaleLowerCase())"
11
+ :multiple="false"
12
+ :loading="loading || fetching"
13
+ >
14
+ <template #option="{ option }">
15
+ <div class="flex items-center space-x-2">
16
+ <OrganizationLogo
17
+ :organization="option"
18
+ size-class="size-8"
19
+ class="flex-none"
20
+ />
21
+ <span>{{ option.name }}</span>
22
+ </div>
23
+ </template>
24
+ </SearchableSelect>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { ofetch } from 'ofetch'
29
+ import { useComponentsConfig } from '../../config'
30
+ import { useTranslation } from '../../composables/useTranslation'
31
+ import { useAsyncSelectModelSync } from '../../composables/useSelectModelSync'
32
+ import type { Organization, OrganizationSuggest } from '../../types/organizations'
33
+ import OrganizationLogo from '../OrganizationLogo.vue'
34
+ import SearchableSelect from './SearchableSelect.vue'
35
+
36
+ const model = defineModel<Organization | OrganizationSuggest | null>({ default: null })
37
+ const id = defineModel<string | undefined>('id')
38
+
39
+ defineProps<{
40
+ loading?: boolean
41
+ }>()
42
+
43
+ const config = useComponentsConfig()
44
+ const { t } = useTranslation()
45
+
46
+ const { fetching } = useAsyncSelectModelSync({
47
+ model,
48
+ id,
49
+ getId: org => org.id,
50
+ fetchById: orgId => ofetch<Organization>(`/api/1/organizations/${orgId}/`, { baseURL: config.apiBase }),
51
+ })
52
+
53
+ async function suggestOrganizations(q: string): Promise<Array<Organization | OrganizationSuggest>> {
54
+ return await ofetch<Array<OrganizationSuggest>>('/api/1/organizations/suggest/', {
55
+ baseURL: config.apiBase,
56
+ query: {
57
+ q,
58
+ size: 20,
59
+ },
60
+ })
61
+ }
62
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="selected"
4
+ :options="organizationTypes"
5
+ :label="t(`Type d'organisation`)"
6
+ :placeholder="t('Tous les types')"
7
+ :get-option-id="(opt) => opt.type"
8
+ :display-value="(value) => value.label"
9
+ :multiple="false"
10
+ >
11
+ <template #option="{ option }">
12
+ {{ option.label }}
13
+ </template>
14
+ </SearchableSelect>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { computed } from 'vue'
19
+ import { getOrganizationTypes, OTHER, USER } from '../../functions/organizations'
20
+ import { useTranslation } from '../../composables/useTranslation'
21
+ import SearchableSelect from './SearchableSelect.vue'
22
+
23
+ const model = defineModel<string | undefined>()
24
+
25
+ const { t } = useTranslation()
26
+
27
+ const organizationTypes = getOrganizationTypes()
28
+ .filter(t => t.type !== OTHER && t.type !== USER)
29
+
30
+ const selected = computed({
31
+ get: () => organizationTypes.find(t => t.type === model.value) ?? null,
32
+ set: (value) => { model.value = value?.type },
33
+ })
34
+ </script>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="topics ?? []"
5
+ :loading="status === 'pending'"
6
+ :label="t('Thématique')"
7
+ :placeholder="t('Toutes les thématiques')"
8
+ :get-option-id="(topic: ReuseTopic) => topic.id"
9
+ :display-value="(topic: ReuseTopic) => topic.label"
10
+ :multiple="false"
11
+ />
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { useTranslation } from '../../composables/useTranslation'
16
+ import { useSelectModelSync } from '../../composables/useSelectModelSync'
17
+ import { useFetch } from '../../functions/api'
18
+ import type { ReuseTopic } from '../../types/reuses'
19
+ import SearchableSelect from './SearchableSelect.vue'
20
+
21
+ const model = defineModel<ReuseTopic | null>({ default: null })
22
+ const id = defineModel<string | undefined>('id')
23
+
24
+ const { t } = useTranslation()
25
+
26
+ const { data: topics, status } = await useFetch<ReuseTopic[]>('/api/1/reuses/topics/', { lazy: true })
27
+
28
+ useSelectModelSync({ model, id, items: topics, getId: topic => topic.id })
29
+ </script>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <SearchableSelect
3
+ v-model="model"
4
+ :options="schemas ?? []"
5
+ :loading="status === 'pending'"
6
+ :label="t('Schéma')"
7
+ :explanation="t('Les schémas de données permettent de décrire des modèles de données.')"
8
+ :placeholder="t('Tous les schémas')"
9
+ :get-option-id="(s: RegisteredSchema) => s.name"
10
+ :display-value="(s: RegisteredSchema) => s.name"
11
+ :multiple="false"
12
+ />
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { useTranslation } from '../../composables/useTranslation'
17
+ import { useSelectModelSync } from '../../composables/useSelectModelSync'
18
+ import { useFetch } from '../../functions/api'
19
+ import type { RegisteredSchema } from '../../types/schemas'
20
+ import SearchableSelect from './SearchableSelect.vue'
21
+
22
+ const model = defineModel<RegisteredSchema | null>({ default: null })
23
+ const id = defineModel<string | undefined>('id')
24
+
25
+ const { t } = useTranslation()
26
+
27
+ const { data: schemas, status } = await useFetch<RegisteredSchema[]>('/api/1/datasets/schemas/', { lazy: true })
28
+
29
+ useSelectModelSync({ model, id, items: schemas, getId: s => s.name })
30
+ </script>