@datagouv/components-next 1.2.0 → 1.4.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 (138) hide show
  1. package/README.md +7 -6
  2. package/dist/{Control-ZFh5ta_U.js → Control-B9WQxlpJ.js} +1 -1
  3. package/dist/{Datafair.client-rf4T1IkA.js → Datafair.client-D_6yzJUG.js} +9 -9
  4. package/dist/{Event-DSQcW7OF.js → Event-iXDrp-fy.js} +11 -11
  5. package/dist/{Image-BijNEG0p.js → Image-mNMBOofs.js} +5 -5
  6. package/dist/ImagePreview.client-B0iPhFm3.js +36 -0
  7. package/dist/{JsonPreview.client-dzar6iuh.js → JsonPreview.client-DSl1kiwC.js} +5 -5
  8. package/dist/{Map-BUtPf5GN.js → Map-BfqKMw0S.js} +1306 -1166
  9. package/dist/{MapContainer.client-D-MoRNhG.js → MapContainer.client-BSfpk_rT.js} +15 -15
  10. package/dist/{OSM-D4MTdBtk.js → OSM-CcrUhItr.js} +15 -23
  11. package/dist/{PdfPreview.client-DoDYLmJD.js → PdfPreview.client-BANFeM6K.js} +441 -434
  12. package/dist/Pmtiles.client-DH9ZrsZR.js +26333 -0
  13. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-I8EZCgzp.js +60 -0
  14. package/dist/{ScaleLine-hJQIqcZm.js → ScaleLine-VGQ7nkMS.js} +2 -2
  15. package/dist/{Tile-Dcl7oIVu.js → Tile-CSpn0Ca8.js} +153 -156
  16. package/dist/{TileImage-BJeHipMX.js → TileImage-CpbaEFwd.js} +143 -131
  17. package/dist/{View-xp_P_OHw.js → View-BYBpt-AU.js} +167 -117
  18. package/dist/{XmlPreview.client-cOhwff6P.js → XmlPreview.client-KCB5mwVf.js} +5 -5
  19. package/dist/{common-BjQlan3k.js → common-BoeTUnDZ.js} +26 -26
  20. package/dist/components-next.css +1 -52
  21. package/dist/components-next.js +201 -170
  22. package/dist/components.css +2 -2
  23. package/dist/{index-NofRBuyf.js → index-DHWzX5vK.js} +5999 -5472
  24. package/dist/{leaflet-src-7m1mB8LI.js → leaflet-src-pVQfonBI.js} +162 -164
  25. package/dist/{main-Iz1ZCL6k.js → main-BDcYkhOc.js} +36671 -29402
  26. package/dist/{proj-CsNo9yH1.js → proj-DxGbobp7.js} +312 -296
  27. package/dist/{text-clamp.esm-B5kW_XMt.js → text-clamp.esm-DVseBqZZ.js} +4 -4
  28. package/dist/{tilecoord-A0fLnBZr.js → tilecoord-DvX7WWiA.js} +264 -255
  29. package/dist/{vue3-json-viewer-BXwup7nO.js → vue3-json-viewer-CJLQFzXZ.js} +10 -16
  30. package/dist/{vue3-xml-viewer.common-tVI9uXUz.js → vue3-xml-viewer.common-Bdcn54ST.js} +1 -1
  31. package/package.json +40 -39
  32. package/src/components/ActivityList/ActivityList.vue +21 -12
  33. package/src/components/AppLink.vue +3 -0
  34. package/src/components/BannerAction.vue +6 -2
  35. package/src/components/Chart/ChartViewer.vue +111 -17
  36. package/src/components/Chart/ChartViewerWrapper.vue +28 -16
  37. package/src/components/ChartCard.vue +112 -0
  38. package/src/components/CopyButton.vue +6 -2
  39. package/src/components/DataserviceCard.vue +23 -6
  40. package/src/components/DataserviceQuality.vue +82 -0
  41. package/src/components/DataserviceQualityInline.vue +31 -0
  42. package/src/components/DataserviceQualityTooltipContent.vue +79 -0
  43. package/src/components/DatasetCard.vue +17 -6
  44. package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -4
  45. package/src/components/DatasetQuality.vue +11 -11
  46. package/src/components/DatasetQualityInline.vue +2 -2
  47. package/src/components/DatasetQualityTooltipContent.vue +1 -1
  48. package/src/components/DiscussionMessageCard.vue +14 -15
  49. package/src/components/Form/SchemaSelect.vue +2 -0
  50. package/src/components/FormattedDate.vue +69 -0
  51. package/src/components/LoadingBlock.vue +4 -1
  52. package/src/components/ObjectCard.vue +4 -1
  53. package/src/components/ObjectCardOwner.vue +13 -1
  54. package/src/components/Pagination.vue +18 -58
  55. package/src/components/Placeholder.vue +3 -2
  56. package/src/components/PostCard.vue +13 -15
  57. package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
  58. package/src/components/ResourceAccordion/Downloads.vue +19 -7
  59. package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
  60. package/src/components/ResourceAccordion/MapContainer.client.vue +1 -8
  61. package/src/components/ResourceAccordion/Metadata.vue +21 -5
  62. package/src/components/ResourceAccordion/PdfPreview.client.vue +36 -12
  63. package/src/components/ResourceAccordion/PdfSkeleton.vue +44 -0
  64. package/src/components/ResourceAccordion/Pmtiles.client.vue +30 -19
  65. package/src/components/ResourceAccordion/Preview.vue +8 -4
  66. package/src/components/ResourceAccordion/PreviewWrapper.vue +17 -10
  67. package/src/components/ResourceAccordion/ResourceAccordion.vue +31 -11
  68. package/src/components/ResourceExplorer/ResourceExplorer.vue +105 -210
  69. package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +79 -0
  70. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +104 -71
  71. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +140 -184
  72. package/src/components/ResourceExplorer/ResourceMainAction.vue +240 -0
  73. package/src/components/ResourceExplorer/ResourceSelector.vue +24 -86
  74. package/src/components/ResourceExplorer/ResourceViewerHeader.vue +124 -0
  75. package/src/components/ResourceExplorer/ResourceViewerSkeleton.vue +96 -0
  76. package/src/components/ResourceListItem.vue +168 -0
  77. package/src/components/ReuseCard.vue +18 -6
  78. package/src/components/ReuseDetails.vue +2 -2
  79. package/src/components/ReuseHorizontalCard.vue +4 -3
  80. package/src/components/SchemaCard.vue +10 -1
  81. package/src/components/Search/Filter/AccessTypeFilter.vue +2 -2
  82. package/src/components/Search/GlobalSearch.vue +28 -10
  83. package/src/components/Search/SearchInput.vue +1 -1
  84. package/src/components/Search/Sidemenu.vue +4 -3
  85. package/src/components/SmallChart.vue +11 -10
  86. package/src/components/StatBox.vue +13 -5
  87. package/src/components/TabularExplorer/TabularActiveFilters.vue +79 -0
  88. package/src/components/TabularExplorer/TabularCell.vue +7 -8
  89. package/src/components/TabularExplorer/TabularCellPopover.vue +21 -5
  90. package/src/components/TabularExplorer/TabularColumnsMenu.vue +112 -0
  91. package/src/components/TabularExplorer/TabularDateField.vue +41 -0
  92. package/src/components/TabularExplorer/TabularDateFilter.vue +403 -0
  93. package/src/components/TabularExplorer/TabularExplorer.vue +127 -780
  94. package/src/components/TabularExplorer/TabularFilterContent.vue +48 -38
  95. package/src/components/TabularExplorer/TabularFilterPopover.vue +27 -32
  96. package/src/components/TabularExplorer/TabularMobileFilterButton.vue +21 -0
  97. package/src/components/TabularExplorer/TabularMobileFilters.vue +150 -0
  98. package/src/components/TabularExplorer/TabularRowsInfo.vue +31 -0
  99. package/src/components/TabularExplorer/TabularSkeleton.vue +92 -0
  100. package/src/components/TabularExplorer/TabularTable.vue +484 -0
  101. package/src/components/TabularExplorer/TabularToolbar.vue +25 -0
  102. package/src/components/TabularExplorer/types.ts +40 -28
  103. package/src/components/TabularExplorer/useColumnMetadata.ts +98 -0
  104. package/src/components/TabularExplorer/useTabularContext.ts +82 -0
  105. package/src/components/TopicCard.vue +15 -14
  106. package/src/composables/useActiveDescendant.ts +5 -0
  107. package/src/composables/useDatasetResources.ts +164 -0
  108. package/src/composables/useHasTabularData.ts +2 -1
  109. package/src/composables/useResizable.ts +46 -0
  110. package/src/composables/useResourceCapabilities.ts +48 -40
  111. package/src/composables/useSearchFilter.ts +7 -5
  112. package/src/composables/useTranslation.ts +24 -9
  113. package/src/config.ts +1 -0
  114. package/src/functions/api.ts +13 -7
  115. package/src/functions/charts.ts +32 -1
  116. package/src/functions/dates.ts +26 -7
  117. package/src/functions/helpers.ts +15 -0
  118. package/src/functions/metrics.ts +57 -56
  119. package/src/functions/owned.ts +21 -0
  120. package/src/functions/paginate.ts +46 -0
  121. package/src/functions/resourceCapabilities.ts +34 -0
  122. package/src/functions/resources.ts +88 -0
  123. package/src/functions/schemas.ts +27 -0
  124. package/src/functions/scroll.ts +20 -0
  125. package/src/functions/tabular.ts +222 -5
  126. package/src/functions/tabularApi.ts +1 -43
  127. package/src/main.ts +32 -6
  128. package/src/types/dataservices.ts +15 -0
  129. package/src/types/organizations.ts +10 -0
  130. package/src/types/resources.ts +0 -1
  131. package/src/types/reuses.ts +12 -1
  132. package/src/types/search.ts +2 -2
  133. package/src/types/visualizations.ts +5 -0
  134. package/dist/Pmtiles.client-Dzm01Zfm.js +0 -25185
  135. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-BRNYswg3.js +0 -61
  136. /package/src/components/{DatasetQualityItem.vue → QualityItem.vue} +0 -0
  137. /package/src/components/{DatasetQualityItemWarning.vue → QualityItemWarning.vue} +0 -0
  138. /package/src/components/{DatasetQualityScore.vue → QualityScore.vue} +0 -0
@@ -0,0 +1,112 @@
1
+ <template>
2
+ <ObjectCard media-size="xl">
3
+ <template #badge>
4
+ <ObjectCardBadge
5
+ v-if="chart.deleted_at"
6
+ :icon="RiDeleteBinLine"
7
+ >
8
+ {{ t('Supprimé') }}
9
+ </ObjectCardBadge>
10
+ <ObjectCardBadge
11
+ v-else-if="chart.private"
12
+ :icon="RiLockLine"
13
+ >
14
+ {{ t('Brouillon') }}
15
+ </ObjectCardBadge>
16
+ </template>
17
+
18
+ <template #media>
19
+ <img
20
+ v-if="chart.image"
21
+ :src="chart.image"
22
+ class="w-full h-full object-cover"
23
+ :alt="chart.title"
24
+ >
25
+ <Placeholder
26
+ v-else
27
+ type="Chart"
28
+ class="w-full h-full"
29
+ />
30
+ </template>
31
+
32
+ <ObjectCardHeader
33
+ :icon="chartIcon"
34
+ :url="chartUrl || chart.page"
35
+ >
36
+ {{ chart.title }}
37
+ </ObjectCardHeader>
38
+
39
+ <div
40
+ v-if="chart.organization || chart.owner"
41
+ class="text-sm flex flex-wrap gap-y-1 items-center truncate"
42
+ >
43
+ <ObjectCardOwner
44
+ :organization="chart.organization"
45
+ :owner="chart.owner"
46
+ :organization-url="organizationUrl"
47
+ />
48
+ <RiSubtractLine
49
+ aria-hidden="true"
50
+ class="size-4 flex-none fill-gray-medium"
51
+ />
52
+ <TranslationT
53
+ tag="p"
54
+ class="text-sm whitespace-nowrap mb-0 text-gray-medium"
55
+ keypath="Mis à jour {date}"
56
+ >
57
+ <template #date>
58
+ <FormattedDate
59
+ :date="chart.last_modified"
60
+ format="relative"
61
+ :options="{ dateStyle: 'medium' }"
62
+ />
63
+ </template>
64
+ </TranslationT>
65
+ </div>
66
+
67
+ <div class="mx-0 -mb-1 flex flex-wrap items-center text-sm text-gray-medium mt-1">
68
+ <p
69
+ class="text-sm mb-0 flex items-center gap-0.5"
70
+ :aria-label="t('{n} vues | {n} vue | {n} vues', chart.metrics.views)"
71
+ >
72
+ <RiEyeLine
73
+ aria-hidden="true"
74
+ class="size-3.5"
75
+ />{{ summarize(chart.metrics.views) }}
76
+ </p>
77
+ </div>
78
+
79
+ <ObjectCardShortDescription :text="chart.description" />
80
+
81
+ <slot />
82
+ </ObjectCard>
83
+ </template>
84
+
85
+ <script setup lang="ts">
86
+ import { computed } from 'vue'
87
+ import { RiBarChartBoxLine, RiDeleteBinLine, RiEyeLine, RiLineChartLine, RiLockLine, RiSubtractLine } from '@remixicon/vue'
88
+ import type { RouteLocationRaw } from 'vue-router'
89
+ import type { Chart } from '../types/visualizations'
90
+ import { summarize } from '../functions/helpers'
91
+ import { useTranslation } from '../composables/useTranslation'
92
+ import Placeholder from './Placeholder.vue'
93
+ import FormattedDate from './FormattedDate.vue'
94
+ import ObjectCard from './ObjectCard.vue'
95
+ import ObjectCardBadge from './ObjectCardBadge.vue'
96
+ import ObjectCardHeader from './ObjectCardHeader.vue'
97
+ import ObjectCardOwner from './ObjectCardOwner.vue'
98
+ import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
99
+ import TranslationT from './TranslationT.vue'
100
+
101
+ const props = defineProps<{
102
+ chart: Chart
103
+ chartUrl?: RouteLocationRaw
104
+ organizationUrl?: RouteLocationRaw
105
+ }>()
106
+
107
+ const { t } = useTranslation()
108
+
109
+ const chartIcon = computed(() => {
110
+ return props.chart.series[0]?.type === 'line' ? RiLineChartLine : RiBarChartBoxLine
111
+ })
112
+ </script>
@@ -17,7 +17,7 @@
17
17
  />
18
18
  <span
19
19
  class="copy-label"
20
- :class="{ 'sr-only': hideLabel }"
20
+ :class="{ 'sr-only': hideLabel || iconOnly }"
21
21
  >{{ copiedLabel }}</span>
22
22
  </span>
23
23
  <span
@@ -32,7 +32,7 @@
32
32
  />
33
33
  <span
34
34
  class="copy-link copy-label"
35
- :class="{ 'sr-only': hideLabel }"
35
+ :class="{ 'sr-only': hideLabel || iconOnly }"
36
36
  >{{ label }}</span>
37
37
  </span>
38
38
  </button>
@@ -49,9 +49,13 @@ const props = withDefaults(defineProps<{
49
49
  label: string
50
50
  copiedLabel: string
51
51
  hideLabel?: boolean
52
+ // Like hideLabel but keeps the default icon and has no bordered box — just the
53
+ // plain copy icon with an sr-only label.
54
+ iconOnly?: boolean
52
55
  reverse?: boolean
53
56
  }>(), {
54
57
  hideLabel: false,
58
+ iconOnly: false,
55
59
  reverse: false,
56
60
  })
57
61
 
@@ -71,9 +71,19 @@
71
71
  class="size-4 flex-none fill-gray-medium"
72
72
  />
73
73
  <!-- https://github.com/datagouv/cdata/issues/653 -->
74
- <p class="text-sm whitespace-nowrap mb-0 text-gray-medium">
75
- {{ t('Mis à jour {date}', { date: formatRelativeIfRecentDate(dataservice.metadata_modified_at, { dateStyle: 'medium' }) }) }}
76
- </p>
74
+ <TranslationT
75
+ tag="p"
76
+ class="text-sm whitespace-nowrap mb-0 text-gray-medium"
77
+ keypath="Mis à jour {date}"
78
+ >
79
+ <template #date>
80
+ <FormattedDate
81
+ :date="dataservice.metadata_modified_at"
82
+ format="relative"
83
+ :options="{ dateStyle: 'medium' }"
84
+ />
85
+ </template>
86
+ </TranslationT>
77
87
  <RiSubtractLine
78
88
  aria-hidden="true"
79
89
  class="size-4 flex-none fill-gray-medium"
@@ -99,6 +109,11 @@
99
109
  </p>
100
110
  </div>
101
111
  </div>
112
+ <DataserviceQualityInline
113
+ v-if="dataservice.quality"
114
+ :quality="dataservice.quality"
115
+ />
116
+
102
117
  <ObjectCardShortDescription
103
118
  v-if="showDescription"
104
119
  :text="dataservice.description"
@@ -113,7 +128,6 @@ import { computed } from 'vue'
113
128
  import type { RouteLocationRaw } from 'vue-router'
114
129
  import { RiArchiveLine, RiEyeLine, RiLockLine, RiPassValidLine, RiSparklingLine, RiStarLine, RiSubtractLine, RiTerminalLine } from '@remixicon/vue'
115
130
  import { useComponentsConfig } from '../config'
116
- import { useFormatDate } from '../functions/dates'
117
131
  import { summarize } from '../functions/helpers'
118
132
  import type { Dataservice } from '../types/dataservices'
119
133
  import type { TitleTag } from '../types/ui'
@@ -126,11 +140,15 @@ import ObjectCardBadge from './ObjectCardBadge.vue'
126
140
  import ObjectCardHeader from './ObjectCardHeader.vue'
127
141
  import ObjectCardOwner from './ObjectCardOwner.vue'
128
142
  import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
143
+ import DataserviceQualityInline from './DataserviceQualityInline.vue'
144
+ import FormattedDate from './FormattedDate.vue'
145
+ import TranslationT from './TranslationT.vue'
129
146
 
130
147
  type Props = {
131
148
  dataservice: Dataservice
132
149
  dataserviceUrl?: RouteLocationRaw
133
- organizationUrl?: RouteLocationRaw
150
+ // undefined falls back to the organization's data.gouv.fr page; pass null to render plain, non-linked text
151
+ organizationUrl?: RouteLocationRaw | null
134
152
  showDescription?: boolean
135
153
  titleTag?: TitleTag
136
154
  }
@@ -140,7 +158,6 @@ const props = withDefaults(defineProps<Props>(), {
140
158
  })
141
159
 
142
160
  const { t } = useTranslation()
143
- const { formatRelativeIfRecentDate } = useFormatDate()
144
161
 
145
162
  const config = useComponentsConfig()
146
163
  const isTabularApi = computed(() => {
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <Toggletip
3
+ :styled-button="false"
4
+ button-class="flex items-center 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
+ <QualityScore
8
+ :score="quality.score"
9
+ class="w-full"
10
+ />
11
+ <RiInformationLine
12
+ class="size-5 shrink-0"
13
+ aria-hidden="true"
14
+ />
15
+ <template #toggletip>
16
+ <DataserviceQualityTooltipContent :quality />
17
+ </template>
18
+ </Toggletip>
19
+ <template v-if="!hideWarnings">
20
+ <ul class="list-none pl-0">
21
+ <QualityItemWarning
22
+ :quality-item="quality.has_description"
23
+ :message="t('Description non renseignée')"
24
+ />
25
+ <QualityItemWarning
26
+ :quality-item="quality.has_machine_documentation"
27
+ :message="t('Documentation machine (OpenAPI) manquante')"
28
+ />
29
+ <QualityItemWarning
30
+ :quality-item="quality.has_technical_documentation"
31
+ :message="t('Documentation technique manquante')"
32
+ />
33
+ <QualityItemWarning
34
+ :quality-item="quality.has_business_documentation"
35
+ :message="t('Documentation métier manquante')"
36
+ />
37
+ <QualityItemWarning
38
+ :quality-item="quality.license"
39
+ :message="t('Licence non renseignée')"
40
+ />
41
+ <QualityItemWarning
42
+ :quality-item="quality.has_contact_point"
43
+ :message="t('Point de contact non renseigné')"
44
+ />
45
+ <QualityItemWarning
46
+ :quality-item="quality.has_base_api_url"
47
+ :message="t(`URL de base de l'API non renseignée`)"
48
+ />
49
+ <QualityItemWarning
50
+ :quality-item="quality.availability_documented"
51
+ :message="t('Disponibilité non documentée')"
52
+ />
53
+ <QualityItemWarning
54
+ :quality-item="quality.rate_limiting_documented"
55
+ :message="t(`Limite d'appels non documentée`)"
56
+ />
57
+ <QualityItemWarning
58
+ :quality-item="quality.access_conditions_clear"
59
+ :message="t(`Conditions d'accès non précisées`)"
60
+ />
61
+ </ul>
62
+ </template>
63
+ </template>
64
+
65
+ <script setup lang="ts">
66
+ import { RiInformationLine } from '@remixicon/vue'
67
+ import type { DataserviceQuality } from '../types/dataservices'
68
+ import QualityScore from './QualityScore.vue'
69
+ import QualityItemWarning from './QualityItemWarning.vue'
70
+ import DataserviceQualityTooltipContent from './DataserviceQualityTooltipContent.vue'
71
+ import Toggletip from './Toggletip.vue'
72
+ import { useTranslation } from '../composables/useTranslation'
73
+
74
+ withDefaults(defineProps<{
75
+ quality: DataserviceQuality
76
+ hideWarnings?: boolean
77
+ }>(), {
78
+ hideWarnings: false,
79
+ })
80
+
81
+ const { t } = useTranslation()
82
+ </script>
@@ -0,0 +1,31 @@
1
+ <template>
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
+ <QualityScore :score="quality.score" />
11
+ <template #toggletip>
12
+ <DataserviceQualityTooltipContent :quality />
13
+ </template>
14
+ </Toggletip>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { RiInformationLine } from '@remixicon/vue'
20
+ import type { DataserviceQuality } from '../types/dataservices'
21
+ import QualityScore from './QualityScore.vue'
22
+ import DataserviceQualityTooltipContent from './DataserviceQualityTooltipContent.vue'
23
+ import Toggletip from './Toggletip.vue'
24
+ import { useTranslation } from '../composables/useTranslation'
25
+
26
+ defineProps<{
27
+ quality: DataserviceQuality
28
+ }>()
29
+
30
+ const { t } = useTranslation()
31
+ </script>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <p class="text-sm text-gray-plain font-bold mb-0">
3
+ {{ t("Qualité des métadonnées :") }}
4
+ </p>
5
+ <ul class="list-none pl-0 space-y-2">
6
+ <QualityItem
7
+ :passed="quality.has_description"
8
+ :message-passed="t('Description renseignée')"
9
+ :message-failed="t('Description non renseignée')"
10
+ class="pb-0"
11
+ />
12
+ <QualityItem
13
+ :passed="quality.has_machine_documentation"
14
+ :message-passed="t('Documentation machine (OpenAPI) disponible')"
15
+ :message-failed="t('Documentation machine (OpenAPI) manquante')"
16
+ class="pb-0"
17
+ />
18
+ <QualityItem
19
+ :passed="quality.has_technical_documentation"
20
+ :message-passed="t('Documentation technique renseignée')"
21
+ :message-failed="t('Documentation technique manquante')"
22
+ class="pb-0"
23
+ />
24
+ <QualityItem
25
+ :passed="quality.has_business_documentation"
26
+ :message-passed="t('Documentation métier renseignée')"
27
+ :message-failed="t('Documentation métier manquante')"
28
+ class="pb-0"
29
+ />
30
+ <QualityItem
31
+ :passed="quality.license"
32
+ :message-passed="t('Licence renseignée')"
33
+ :message-failed="t('Licence non renseignée')"
34
+ class="pb-0"
35
+ />
36
+ <QualityItem
37
+ :passed="quality.has_contact_point"
38
+ :message-passed="t('Point de contact renseigné')"
39
+ :message-failed="t('Point de contact non renseigné')"
40
+ class="pb-0"
41
+ />
42
+ <QualityItem
43
+ :passed="quality.has_base_api_url"
44
+ :message-passed="t(`URL de base de l'API renseignée`)"
45
+ :message-failed="t(`URL de base de l'API non renseignée`)"
46
+ class="pb-0"
47
+ />
48
+ <QualityItem
49
+ :passed="quality.availability_documented"
50
+ :message-passed="t('Disponibilité documentée')"
51
+ :message-failed="t('Disponibilité non documentée')"
52
+ class="pb-0"
53
+ />
54
+ <QualityItem
55
+ :passed="quality.rate_limiting_documented"
56
+ :message-passed="t(`Limite d'appels documentée`)"
57
+ :message-failed="t(`Limite d'appels non documentée`)"
58
+ class="pb-0"
59
+ />
60
+ <QualityItem
61
+ :passed="quality.access_conditions_clear"
62
+ :message-passed="t(`Conditions d'accès claires`)"
63
+ :message-failed="t(`Conditions d'accès non précisées`)"
64
+ class="pb-0"
65
+ />
66
+ </ul>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ import type { DataserviceQuality } from '../types/dataservices'
71
+ import { useTranslation } from '../composables/useTranslation'
72
+ import QualityItem from './QualityItem.vue'
73
+
74
+ defineProps<{
75
+ quality: DataserviceQuality
76
+ }>()
77
+
78
+ const { t } = useTranslation()
79
+ </script>
@@ -56,9 +56,19 @@
56
56
  :organization-url="organizationUrl"
57
57
  />
58
58
  <RiSubtractLine class="hidden md:block size-4 flex-none fill-gray-medium" />
59
- <div class="w-full md:w-auto text-gray-medium whitespace-nowrap">
60
- {{ t('Mis à jour {date}', { date: formatRelativeIfRecentDate(dataset.last_update, { dateStyle: 'medium' }) }) }}
61
- </div>
59
+ <TranslationT
60
+ tag="div"
61
+ class="w-full md:w-auto text-gray-medium whitespace-nowrap"
62
+ keypath="Mis à jour {date}"
63
+ >
64
+ <template #date>
65
+ <FormattedDate
66
+ :date="dataset.last_update"
67
+ format="relative"
68
+ :options="{ dateStyle: 'medium' }"
69
+ />
70
+ </template>
71
+ </TranslationT>
62
72
  </div>
63
73
  <div class="mx-0 -mb-1 flex flex-wrap items-center text-sm text-gray-medium">
64
74
  <div class="hidden sm:flex text-gray-medium">
@@ -122,7 +132,6 @@ import { RiArchiveLine, RiDatabase2Line, RiDownloadLine, RiEyeLine, RiLineChartL
122
132
  import type { Dataset, DatasetV2 } from '../types/datasets'
123
133
  import type { TitleTag } from '../types/ui'
124
134
  import { summarize } from '../functions/helpers'
125
- import { useFormatDate } from '../functions/dates'
126
135
  import { getDescriptionShort } from '../functions/description'
127
136
  import { useTranslation } from '../composables/useTranslation'
128
137
  import DatasetQualityInline from './DatasetQualityInline.vue'
@@ -134,12 +143,15 @@ import ObjectCard from './ObjectCard.vue'
134
143
  import ObjectCardBadge from './ObjectCardBadge.vue'
135
144
  import ObjectCardHeader from './ObjectCardHeader.vue'
136
145
  import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
146
+ import FormattedDate from './FormattedDate.vue'
147
+ import TranslationT from './TranslationT.vue'
137
148
 
138
149
  type Props = {
139
150
  dataset: Dataset | DatasetV2
140
151
  datasetUrl?: RouteLocationRaw
141
152
  datasetUrlInNewTab?: boolean
142
- organizationUrl?: RouteLocationRaw
153
+ // undefined falls back to the organization's data.gouv.fr page; pass null to render plain, non-linked text
154
+ organizationUrl?: RouteLocationRaw | null
143
155
  showDescriptionShort?: boolean
144
156
  titleTag?: TitleTag
145
157
  }
@@ -149,5 +161,4 @@ const props = withDefaults(defineProps<Props>(), {
149
161
  })
150
162
 
151
163
  const { t } = useTranslation()
152
- const { formatRelativeIfRecentDate } = useFormatDate()
153
164
  </script>
@@ -6,7 +6,9 @@
6
6
  <DescriptionList>
7
7
  <div>
8
8
  <DescriptionListTerm>{{ t('Création') }}</DescriptionListTerm>
9
- <DescriptionListDetails>{{ formatDate(dataset.created_at) }}</DescriptionListDetails>
9
+ <DescriptionListDetails>
10
+ <FormattedDate :date="dataset.created_at" />
11
+ </DescriptionListDetails>
10
12
  </div>
11
13
  <div v-if="dataset.frequency">
12
14
  <DescriptionListTerm>{{ t('Fréquence') }}</DescriptionListTerm>
@@ -20,7 +22,9 @@
20
22
  </div>
21
23
  <div>
22
24
  <DescriptionListTerm>{{ t('Dernière mise à jour') }}</DescriptionListTerm>
23
- <DescriptionListDetails>{{ formatDate(dataset.last_update) }}</DescriptionListDetails>
25
+ <DescriptionListDetails>
26
+ <FormattedDate :date="dataset.last_update" />
27
+ </DescriptionListDetails>
24
28
  </div>
25
29
  <slot />
26
30
  </DescriptionList>
@@ -29,17 +33,16 @@
29
33
 
30
34
  <script setup lang="ts">
31
35
  import { useTranslation } from '../../composables/useTranslation'
32
- import { useFormatDate } from '../../functions/dates'
33
36
  import type { DatasetV2WithFullObject } from '../../types/datasets'
34
37
  import DescriptionList from '../DescriptionList.vue'
35
38
  import DescriptionListTerm from '../DescriptionListTerm.vue'
36
39
  import DescriptionListDetails from '../DescriptionListDetails.vue'
37
40
  import DateRangeDetails from '../DateRangeDetails.vue'
41
+ import FormattedDate from '../FormattedDate.vue'
38
42
 
39
43
  defineProps<{
40
44
  dataset: DatasetV2WithFullObject
41
45
  }>()
42
46
 
43
47
  const { t } = useTranslation()
44
- const { formatDate } = useFormatDate()
45
48
  </script>
@@ -13,7 +13,7 @@
13
13
  {{ t('Qualité des métadonnées:') }}
14
14
  </span>
15
15
  </span>
16
- <DatasetQualityScore
16
+ <QualityScore
17
17
  :score="quality.score"
18
18
  class="w-full"
19
19
  />
@@ -23,35 +23,35 @@
23
23
  </Toggletip>
24
24
  <template v-if="!hideWarnings">
25
25
  <ul class="list-none pl-0">
26
- <DatasetQualityItemWarning
26
+ <QualityItemWarning
27
27
  :quality-item="quality.dataset_description_quality"
28
28
  :message="t('Description des données non renseignée')"
29
29
  />
30
- <DatasetQualityItemWarning
30
+ <QualityItemWarning
31
31
  :quality-item="quality.resources_documentation"
32
32
  :message="t('Documentation des fichiers manquante')"
33
33
  />
34
- <DatasetQualityItemWarning
34
+ <QualityItemWarning
35
35
  :quality-item="quality.license"
36
36
  :message="t('Licence non renseignée')"
37
37
  />
38
- <DatasetQualityItemWarning
38
+ <QualityItemWarning
39
39
  :quality-item="quality.update_frequency && quality.update_fulfilled_in_time"
40
40
  :message="quality.update_frequency ? t('Fréquence de mise à jour non respectée') : t('Fréquence de mise à jour non renseignée')"
41
41
  />
42
- <DatasetQualityItemWarning
42
+ <QualityItemWarning
43
43
  :quality-item="quality.has_open_format"
44
44
  :message="t('Formats de fichiers non standards')"
45
45
  />
46
- <DatasetQualityItemWarning
46
+ <QualityItemWarning
47
47
  :quality-item="quality.temporal_coverage"
48
48
  :message="t('Couverture temporelle non renseignée')"
49
49
  />
50
- <DatasetQualityItemWarning
50
+ <QualityItemWarning
51
51
  :quality-item="quality.spatial"
52
52
  :message="t('Couverture spatiale non renseignée')"
53
53
  />
54
- <DatasetQualityItemWarning
54
+ <QualityItemWarning
55
55
  :quality-item="quality.all_resources_available"
56
56
  :message="t('Certains fichiers ne sont pas disponibles')"
57
57
  />
@@ -62,8 +62,8 @@
62
62
  <script setup lang="ts">
63
63
  import { RiInformationLine } from '@remixicon/vue'
64
64
  import type { Quality } from '../types/datasets'
65
- import DatasetQualityItemWarning from './DatasetQualityItemWarning.vue'
66
- import DatasetQualityScore from './DatasetQualityScore.vue'
65
+ import QualityItemWarning from './QualityItemWarning.vue'
66
+ import QualityScore from './QualityScore.vue'
67
67
  import Toggletip from './Toggletip.vue'
68
68
  import DatasetQualityTooltipContent from './DatasetQualityTooltipContent.vue'
69
69
  import { useTranslation } from '../composables/useTranslation'
@@ -7,7 +7,7 @@
7
7
  >
8
8
  <RiInformationLine class="size-3.5 shrink-0" />
9
9
  <span class="text-gray-medium text-sm group-hover/quality:underline">{{ t('Métadonnées :') }}</span>
10
- <DatasetQualityScore :score="quality.score" />
10
+ <QualityScore :score="quality.score" />
11
11
  <template #toggletip>
12
12
  <DatasetQualityTooltipContent :quality />
13
13
  </template>
@@ -18,7 +18,7 @@
18
18
  <script setup lang="ts">
19
19
  import { RiInformationLine } from '@remixicon/vue'
20
20
  import type { Quality } from '../types/datasets'
21
- import DatasetQualityScore from './DatasetQualityScore.vue'
21
+ import QualityScore from './QualityScore.vue'
22
22
  import DatasetQualityTooltipContent from './DatasetQualityTooltipContent.vue'
23
23
  import Toggletip from './Toggletip.vue'
24
24
  import { useTranslation } from '../composables/useTranslation'
@@ -68,7 +68,7 @@
68
68
  import type { Quality } from '../types/datasets'
69
69
  import { useComponentsConfig } from '../config'
70
70
  import { useTranslation } from '../composables/useTranslation'
71
- import DatasetQualityItem from './DatasetQualityItem.vue'
71
+ import DatasetQualityItem from './QualityItem.vue'
72
72
 
73
73
  defineProps<{
74
74
  quality: Quality
@@ -20,9 +20,18 @@
20
20
  aria-hidden="true"
21
21
  class="size-4 flex-none fill-gray-medium"
22
22
  />
23
- <span class="text-gray-medium whitespace-nowrap">
24
- {{ t('Posté {date}', { date: formatDate(discussion.created) }) }}
25
- </span>
23
+ <TranslationT
24
+ class="text-gray-medium whitespace-nowrap"
25
+ keypath="Posté {date}"
26
+ >
27
+ <template #date>
28
+ <FormattedDate
29
+ :date="discussion.created"
30
+ format="relative"
31
+ :options="{ dateStyle: 'long', timeStyle: 'short' }"
32
+ />
33
+ </template>
34
+ </TranslationT>
26
35
  </div>
27
36
 
28
37
  <ObjectCardShortDescription :text="firstMessageContent" />
@@ -35,13 +44,13 @@
35
44
  import { RiChat3Line, RiSubtractLine } from '@remixicon/vue'
36
45
  import { computed } from 'vue'
37
46
  import type { RouteLocationRaw } from 'vue-router'
38
- import { useFormatDate } from '../functions/dates'
39
- import { useTranslation } from '../composables/useTranslation'
40
47
  import type { Thread } from '../types/discussions'
41
48
  import ObjectCard from './ObjectCard.vue'
42
49
  import ObjectCardHeader from './ObjectCardHeader.vue'
43
50
  import ObjectCardOwner from './ObjectCardOwner.vue'
44
51
  import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
52
+ import FormattedDate from './FormattedDate.vue'
53
+ import TranslationT from './TranslationT.vue'
45
54
 
46
55
  const props = defineProps<{
47
56
  discussion: Thread
@@ -49,15 +58,5 @@ const props = defineProps<{
49
58
  organizationUrl?: RouteLocationRaw
50
59
  }>()
51
60
 
52
- const { t } = useTranslation()
53
- const { formatRelativeIfRecentDate } = useFormatDate()
54
-
55
61
  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
62
  </script>
@@ -8,6 +8,7 @@
8
8
  :placeholder="t('Tous les schémas')"
9
9
  :get-option-id="(s: RegisteredSchema) => s.name"
10
10
  :display-value="(s: RegisteredSchema) => s.name"
11
+ :filter="schemaMatchesQuery"
11
12
  :multiple="false"
12
13
  />
13
14
  </template>
@@ -16,6 +17,7 @@
16
17
  import { useTranslation } from '../../composables/useTranslation'
17
18
  import { useSelectModelSync } from '../../composables/useSelectModelSync'
18
19
  import { useFetch } from '../../functions/api'
20
+ import { schemaMatchesQuery } from '../../functions/schemas'
19
21
  import type { RegisteredSchema } from '../../types/schemas'
20
22
  import SearchableSelect from './SearchableSelect.vue'
21
23