@datagouv/components-next 0.2.0 → 1.0.1

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 (155) hide show
  1. package/README.md +1 -1
  2. package/assets/main.css +49 -22
  3. package/dist/Control-BNCDn-8E.js +148 -0
  4. package/dist/{Datafair.client-x39O4yfF.js → Datafair.client-B5lBpOl8.js} +2 -2
  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-Doz1Z0BS.js} +23 -23
  8. package/dist/Map-BdT3i2C4.js +7609 -0
  9. package/dist/MapContainer.client-oiieO8H-.js +105 -0
  10. package/dist/OSM-CamriM9b.js +71 -0
  11. package/dist/PdfPreview.client-CdAhkDFJ.js +14513 -0
  12. package/dist/{Pmtiles.client-BaiIo4VZ.js → Pmtiles.client-B0v8tGJQ.js} +3 -3
  13. package/dist/ScaleLine-BiesrgOv.js +165 -0
  14. package/dist/Swagger.client-CsK65JnG.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-CrjHf74q.js} +17 -17
  19. package/dist/common-C4rDcQpp.js +243 -0
  20. package/dist/components-next.css +1 -1
  21. package/dist/components-next.js +158 -117
  22. package/dist/components.css +1 -1
  23. package/dist/{MapContainer.client-DeSo8EvG.js → index-Bbu9rOHt.js} +4975 -21416
  24. package/dist/leaflet-src-7m1mB8LI.js +6338 -0
  25. package/dist/{main-Dgri3TQL.js → main-CiH8ZmBI.js} +56973 -51462
  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-Bi_bsV6C.js} +1 -1
  29. package/package.json +6 -2
  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 +85 -120
  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/DatasetQuality.vue +23 -16
  46. package/src/components/DatasetQualityInline.vue +13 -17
  47. package/src/components/DatasetQualityScore.vue +12 -15
  48. package/src/components/DatasetQualityTooltipContent.vue +3 -3
  49. package/src/components/DescriptionList.vue +1 -4
  50. package/src/components/DescriptionListDetails.vue +5 -0
  51. package/src/components/DescriptionListTerm.vue +5 -0
  52. package/src/components/DiscussionMessageCard.vue +63 -0
  53. package/src/components/ExtraAccordion.vue +4 -4
  54. package/src/components/Form/BadgeSelect.vue +35 -0
  55. package/src/components/Form/FormatSelect.vue +28 -0
  56. package/src/components/Form/GeozoneSelect.vue +52 -0
  57. package/src/components/Form/GranularitySelect.vue +29 -0
  58. package/src/components/Form/LicenseSelect.vue +30 -0
  59. package/src/components/Form/OrganizationSelect.vue +62 -0
  60. package/src/components/Form/OrganizationTypeSelect.vue +34 -0
  61. package/src/components/Form/ReuseTopicSelect.vue +29 -0
  62. package/src/components/Form/SchemaSelect.vue +30 -0
  63. package/src/components/Form/SearchableSelect.vue +334 -0
  64. package/src/components/Form/SelectGroup.vue +132 -0
  65. package/src/components/Form/TagSelect.vue +38 -0
  66. package/src/components/LeafletMap.vue +31 -0
  67. package/src/components/LicenseBadge.vue +24 -0
  68. package/src/components/LoadingBlock.vue +23 -2
  69. package/src/components/MarkdownViewer.vue +3 -1
  70. package/src/components/ObjectCard.vue +42 -0
  71. package/src/components/ObjectCardBadge.vue +22 -0
  72. package/src/components/ObjectCardHeader.vue +35 -0
  73. package/src/components/ObjectCardOwner.vue +43 -0
  74. package/src/components/ObjectCardShortDescription.vue +28 -0
  75. package/src/components/OrganizationCard.vue +35 -20
  76. package/src/components/OrganizationHorizontalCard.vue +87 -0
  77. package/src/components/OrganizationLogo.vue +1 -1
  78. package/src/components/OrganizationNameWithCertificate.vue +12 -6
  79. package/src/components/OwnerTypeIcon.vue +1 -0
  80. package/src/components/Pagination.vue +1 -1
  81. package/src/components/Placeholder.vue +5 -2
  82. package/src/components/PostCard.vue +62 -0
  83. package/src/components/ProgressBar.vue +31 -0
  84. package/src/components/RadioGroup.vue +32 -0
  85. package/src/components/RadioInput.vue +64 -0
  86. package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
  87. package/src/components/ResourceAccordion/EditButton.vue +2 -3
  88. package/src/components/ResourceAccordion/JsonPreview.client.vue +3 -3
  89. package/src/components/ResourceAccordion/MapContainer.client.vue +21 -17
  90. package/src/components/ResourceAccordion/Metadata.vue +11 -24
  91. package/src/components/ResourceAccordion/PdfPreview.client.vue +70 -74
  92. package/src/components/ResourceAccordion/Pmtiles.client.vue +2 -2
  93. package/src/components/ResourceAccordion/Preview.vue +2 -2
  94. package/src/components/ResourceAccordion/ResourceAccordion.vue +35 -28
  95. package/src/components/ResourceAccordion/ResourceIcon.vue +1 -0
  96. package/src/components/ResourceAccordion/SchemaBadge.vue +2 -2
  97. package/src/components/ResourceAccordion/XmlPreview.client.vue +3 -3
  98. package/src/components/ResourceExplorer/ResourceExplorer.vue +243 -0
  99. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +116 -0
  100. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +410 -0
  101. package/src/components/ReuseCard.vue +8 -28
  102. package/src/components/ReuseHorizontalCard.vue +80 -0
  103. package/src/components/Search/BasicAndAdvancedFilters.vue +49 -0
  104. package/src/components/Search/Filter/AccessTypeFilter.vue +37 -0
  105. package/src/components/Search/Filter/DatasetBadgeFilter.vue +40 -0
  106. package/src/components/Search/Filter/FilterButtonGroup.vue +78 -0
  107. package/src/components/Search/Filter/FormatFamilyFilter.vue +39 -0
  108. package/src/components/Search/Filter/LastUpdateRangeFilter.vue +37 -0
  109. package/src/components/Search/Filter/ProducerTypeFilter.vue +49 -0
  110. package/src/components/Search/Filter/ReuseTypeFilter.vue +42 -0
  111. package/src/components/Search/GlobalSearch.vue +707 -0
  112. package/src/components/Search/SearchInput.vue +63 -0
  113. package/src/components/Search/Sidemenu.vue +38 -0
  114. package/src/components/StatBox.vue +5 -5
  115. package/src/components/Tag.vue +30 -0
  116. package/src/components/Toggletip.vue +11 -4
  117. package/src/components/Tooltip.vue +2 -3
  118. package/src/components/TopicCard.vue +134 -0
  119. package/src/components/radioGroupContext.ts +9 -0
  120. package/src/composables/useDebouncedRef.ts +31 -0
  121. package/src/composables/useHasTabularData.ts +15 -0
  122. package/src/composables/useMetrics.ts +4 -3
  123. package/src/composables/useResourceCapabilities.ts +131 -0
  124. package/src/composables/useRouteQueryBoolean.ts +10 -0
  125. package/src/composables/useSelectModelSync.ts +89 -0
  126. package/src/composables/useStableQueryParams.ts +84 -0
  127. package/src/composables/useTranslation.ts +2 -1
  128. package/src/config.ts +4 -0
  129. package/src/functions/api.ts +25 -6
  130. package/src/functions/api.types.ts +5 -3
  131. package/src/functions/datasets.ts +1 -29
  132. package/src/functions/description.ts +33 -0
  133. package/src/functions/helpers.ts +11 -0
  134. package/src/functions/markdown.ts +60 -16
  135. package/src/functions/metrics.ts +33 -0
  136. package/src/functions/organizations.ts +5 -5
  137. package/src/functions/resourceCapabilities.ts +55 -0
  138. package/src/main.ts +96 -7
  139. package/src/types/dataservices.ts +14 -12
  140. package/src/types/datasets.ts +20 -7
  141. package/src/types/discussions.ts +20 -0
  142. package/src/types/licenses.ts +3 -3
  143. package/src/types/organizations.ts +13 -1
  144. package/src/types/owned.ts +4 -2
  145. package/src/types/pages.ts +70 -0
  146. package/src/types/posts.ts +27 -0
  147. package/src/types/resources.ts +16 -0
  148. package/src/types/reuses.ts +14 -5
  149. package/src/types/search.ts +407 -0
  150. package/src/types/users.ts +12 -3
  151. package/dist/PdfPreview.client-COOkEkRA.js +0 -107
  152. package/dist/Swagger.client-CpLgaLg6.js +0 -4
  153. package/dist/pdf-vue3-IkJO65RH.js +0 -273
  154. package/dist/pdf.min-f72cfa08-CdgJTooZ.js +0 -9501
  155. package/src/components/DatasetInformationPanel.vue +0 -211
@@ -1,20 +1,26 @@
1
1
  <template>
2
- <div class="flex items-center">
3
- <Toggletip
4
- :button-props="{ class: '-ml-2 mt-px', title: t('Qualité des métadonnées') }"
5
- >
6
- <template #toggletip>
7
- <DatasetQualityTooltipContent :quality />
8
- </template>
9
- </Toggletip>
10
- <div class="text-sm text-gray-plain font-bold">
11
- {{ t('Qualité des métadonnées:') }}
12
- </div>
13
- </div>
14
- <DatasetQualityScore
15
- :score="quality.score"
16
- class="w-full"
17
- />
2
+ <Toggletip
3
+ :styled-button="false"
4
+ button-class="flex flex-col gap-1 rounded-sm p-1.5 -m-1.5 border-transparent -outline-offset-2 hover:bg-gray-some transition-colors w-full text-left"
5
+ :button-props="{ title: t('Qualité des métadonnées') }"
6
+ >
7
+ <span class="flex items-center gap-1">
8
+ <RiInformationLine
9
+ class="size-5 shrink-0"
10
+ aria-hidden="true"
11
+ />
12
+ <span class="text-sm text-gray-plain font-bold">
13
+ {{ t('Qualité des métadonnées:') }}
14
+ </span>
15
+ </span>
16
+ <DatasetQualityScore
17
+ :score="quality.score"
18
+ class="w-full"
19
+ />
20
+ <template #toggletip>
21
+ <DatasetQualityTooltipContent :quality />
22
+ </template>
23
+ </Toggletip>
18
24
  <template v-if="!hideWarnings">
19
25
  <ul class="list-none pl-0">
20
26
  <DatasetQualityItemWarning
@@ -54,6 +60,7 @@
54
60
  </template>
55
61
 
56
62
  <script setup lang="ts">
63
+ import { RiInformationLine } from '@remixicon/vue'
57
64
  import type { Quality } from '../types/datasets'
58
65
  import DatasetQualityItemWarning from './DatasetQualityItemWarning.vue'
59
66
  import DatasetQualityScore from './DatasetQualityScore.vue'
@@ -1,21 +1,17 @@
1
1
  <template>
2
- <div class="m-0 flex flex-wrap items-center text-sm text-gray-medium">
3
- <div class="fr-grid-row fr-grid-row--middle">
4
- <Toggletip
5
- :button-props="{ class: 'relative z-2 ml-0.5', title: t('Qualité des métadonnées') }"
6
- >
7
- <RiInformationLine class="size-4" />
8
- <template #toggletip>
9
- <DatasetQualityTooltipContent :quality />
10
- </template>
11
- </Toggletip>
12
- <p class="my-0 mr-1 text-gray-medium text-sm">
13
- {{ t('Métadonnées :') }}
14
- </p>
15
- <div class="fr-grid-row fr-grid-row--middle fr-mr-1v">
16
- <DatasetQualityScore :score="quality.score" />
17
- </div>
18
- </div>
2
+ <div class="m-0 text-sm text-gray-medium">
3
+ <Toggletip
4
+ :styled-button="false"
5
+ button-class="border-transparent -outline-offset-2 inline-flex items-center justify-center hover:bg-gray-lower transition-colors"
6
+ :button-props="{ class: 'relative z-2 gap-1 rounded-sm px-1 -mx-1 group/quality', title: t('Qualité des métadonnées') }"
7
+ >
8
+ <RiInformationLine class="size-3.5 shrink-0" />
9
+ <span class="text-gray-medium text-sm group-hover/quality:underline">{{ t('Métadonnées :') }}</span>
10
+ <DatasetQualityScore :score="quality.score" />
11
+ <template #toggletip>
12
+ <DatasetQualityTooltipContent :quality />
13
+ </template>
14
+ </Toggletip>
19
15
  </div>
20
16
  </template>
21
17
 
@@ -1,26 +1,23 @@
1
1
  <template>
2
- <meter
3
- class="quality-score"
4
- :class="props.class"
5
- min="0"
6
- low="0"
7
- :high="high"
8
- :max="quality_max_score"
9
- :optimum="quality_max_score"
2
+ <ProgressBar
10
3
  :value="score"
4
+ :max="quality_max_score"
5
+ :aria-label="score >= high ? t('Bon') : t('À améliorer')"
6
+ :bar-class="score >= high ? 'bg-success-dark' : 'bg-gray-low'"
7
+ :class="props.class"
11
8
  >
12
- <template v-if="score >= high">
13
- {{ t('Bon') }}
14
- </template>
15
- <template v-else>
16
- {{ t('À améliorer') }}
17
- </template>({{ calculatedScore }})
18
- </meter>
9
+ <span class="sr-only">
10
+ <template v-if="score >= high">{{ t('Bon') }}</template>
11
+ <template v-else>{{ t('À améliorer') }}</template>
12
+ ({{ calculatedScore }})
13
+ </span>
14
+ </ProgressBar>
19
15
  </template>
20
16
 
21
17
  <script setup lang="ts">
22
18
  import { computed } from 'vue'
23
19
  import { useTranslation } from '../composables/useTranslation'
20
+ import ProgressBar from './ProgressBar.vue'
24
21
 
25
22
  const props = withDefaults(defineProps<{
26
23
  score: number
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <h5 class="text-sm text-gray-plain font-bold">
2
+ <p class="text-sm text-gray-plain font-bold mb-0">
3
3
  {{ t("Qualité des métadonnées :") }}
4
- </h5>
4
+ </p>
5
5
  <ul class="list-none pl-0 space-y-2">
6
6
  <DatasetQualityItem
7
7
  :passed="quality.dataset_description_quality"
@@ -52,7 +52,7 @@
52
52
  class="pb-0"
53
53
  />
54
54
  </ul>
55
- <div class="fr-grid-row fr-grid-row--right not-enlarged">
55
+ <div class="fr-grid-row fr-grid-row--right">
56
56
  <a
57
57
  :href="config.datasetQualityGuideUrl"
58
58
  target="_blank"
@@ -1,8 +1,5 @@
1
1
  <template>
2
- <dl class="fr-my-0">
2
+ <dl class="grid grid-cols-1 md:grid-cols-3 gap-6 p-0">
3
3
  <slot />
4
4
  </dl>
5
5
  </template>
6
-
7
- <script setup lang="ts">
8
- </script>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <dd class="p-0 text-sm text-gray-medium">
3
+ <slot />
4
+ </dd>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <dt class="mb-1 p-0 text-sm font-bold">
3
+ <slot />
4
+ </dt>
5
+ </template>
@@ -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 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>