@datagouv/components-next 1.0.2-dev.161 → 1.0.2-dev.162

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 (48) hide show
  1. package/dist/{Datafair.client-Bz1l4SLK.js → Datafair.client-DXPU1V24.js} +1 -1
  2. package/dist/{JsonPreview.client-XwLb74J8.js → JsonPreview.client-D1SnGfWG.js} +2 -2
  3. package/dist/{MapContainer.client-DJm7fYDx.js → MapContainer.client-DlsaEVGx.js} +2 -2
  4. package/dist/{PdfPreview.client-CoLz0aZp.js → PdfPreview.client-C9OrLR0z.js} +2 -2
  5. package/dist/{Pmtiles.client-bKmHL2Qg.js → Pmtiles.client-CyylWfTy.js} +5660 -5842
  6. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-CxXJ7rC5.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-CtXZOHXI.js} +10 -7
  7. package/dist/{XmlPreview.client-Baetgqam.js → XmlPreview.client-DoX7RurH.js} +3 -3
  8. package/dist/components-next.css +1 -1
  9. package/dist/components-next.js +171 -178
  10. package/dist/components.css +1 -1
  11. package/dist/{index-Crp28Eov.js → index-Br1sa7wQ.js} +4293 -4392
  12. package/dist/{leaflet-src-CRXb3b2x.js → leaflet-src-DWG7tmpQ.js} +1 -1
  13. package/dist/{main-Cmq8fQdM.js → main-BU6kP4dE.js} +14044 -14487
  14. package/dist/{vue3-xml-viewer.common-H2czi46-.js → vue3-xml-viewer.common-Cpui-Yi9.js} +1 -1
  15. package/package.json +5 -4
  16. package/src/components/Chart/ChartViewer.vue +10 -103
  17. package/src/components/Chart/ChartViewerWrapper.vue +0 -8
  18. package/src/components/DataserviceCard.vue +0 -6
  19. package/src/components/DatasetQuality.vue +11 -11
  20. package/src/components/DatasetQualityInline.vue +2 -2
  21. package/src/components/DatasetQualityTooltipContent.vue +1 -1
  22. package/src/components/ResourceAccordion/ResourceAccordion.vue +3 -8
  23. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +1 -15
  24. package/src/components/ReuseCard.vue +2 -2
  25. package/src/components/ReuseDetails.vue +2 -2
  26. package/src/components/ReuseHorizontalCard.vue +2 -2
  27. package/src/components/Search/GlobalSearch.vue +2 -2
  28. package/src/components/TabularExplorer/TabularExplorer.vue +5 -31
  29. package/src/components/TabularExplorer/types.ts +2 -2
  30. package/src/composables/useHasTabularData.ts +1 -2
  31. package/src/composables/useResourceCapabilities.ts +14 -27
  32. package/src/config.ts +0 -1
  33. package/src/functions/charts.ts +2 -18
  34. package/src/functions/resources.ts +0 -56
  35. package/src/main.ts +5 -12
  36. package/src/types/dataservices.ts +0 -15
  37. package/src/types/organizations.ts +0 -10
  38. package/src/types/reuses.ts +1 -12
  39. package/src/types/search.ts +2 -2
  40. package/src/types/visualizations.ts +1 -1
  41. package/dist/ImagePreview.client-CogDiX0n.js +0 -36
  42. package/src/components/DataserviceQuality.vue +0 -82
  43. package/src/components/DataserviceQualityInline.vue +0 -31
  44. package/src/components/DataserviceQualityTooltipContent.vue +0 -79
  45. package/src/components/ResourceAccordion/ImagePreview.client.vue +0 -48
  46. /package/src/components/{QualityItem.vue → DatasetQualityItem.vue} +0 -0
  47. /package/src/components/{QualityItemWarning.vue → DatasetQualityItemWarning.vue} +0 -0
  48. /package/src/components/{QualityScore.vue → DatasetQualityScore.vue} +0 -0
@@ -1,4 +1,4 @@
1
- import { g as Ke } from "./main-Cmq8fQdM.js";
1
+ import { g as Ke } from "./main-BU6kP4dE.js";
2
2
  import We from "vue";
3
3
  function Fe($, K) {
4
4
  for (var V = 0; V < K.length; V++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagouv/components-next",
3
- "version": "1.0.2-dev.161",
3
+ "version": "1.0.2-dev.162",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -23,7 +23,7 @@
23
23
  "src"
24
24
  ],
25
25
  "dependencies": {
26
- "@floating-ui/vue": "^2.0.1",
26
+ "@floating-ui/vue": "^1.1.11",
27
27
  "@headlessui/vue": "^1.7.23",
28
28
  "@remixicon/vue": "^4.9.0",
29
29
  "@types/hast": "^3.0.4",
@@ -31,7 +31,7 @@
31
31
  "@vueuse/core": "^14.3.0",
32
32
  "@vueuse/router": "^14.3.0",
33
33
  "chart.js": "^4.5.1",
34
- "dompurify": "^3.4.11",
34
+ "dompurify": "^3.4.7",
35
35
  "echarts": "^6.1.0",
36
36
  "geopf-extensions-openlayers": "1.0.0-beta.11",
37
37
  "leaflet": "^1.9.4",
@@ -63,6 +63,7 @@
63
63
  "yaml": "^2.9.0"
64
64
  },
65
65
  "devDependencies": {
66
+ "@intlify/cli": "^0.13.1",
66
67
  "@tailwindcss/cli": "^4.3.0",
67
68
  "@tailwindcss/typography": "^0.5.19",
68
69
  "@tsconfig/node22": "^22.0.5",
@@ -82,7 +83,7 @@
82
83
  "typescript": "^5.9.3",
83
84
  "vite": "^7.3.3",
84
85
  "vite-plugin-vue-devtools": "^8.1.2",
85
- "vue": "^3.5.40",
86
+ "vue": "^3.5.35",
86
87
  "vue-router": "^5.0.7",
87
88
  "vue-tsc": "^3.3.2"
88
89
  },
@@ -13,8 +13,7 @@ import { TitleComponent, TooltipComponent, LegendComponent, GridComponent, Datas
13
13
  import { init, type ECharts as EChartsType } from 'echarts'
14
14
  import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
15
15
  import { summarize } from '../../functions/helpers'
16
- import { useFormatDate } from '../../functions/dates'
17
- import type { Chart, ColumnDefinition, ColumnsDefinition, XAxis, YAxis, XAxisForm, ChartForApi } from '../../types/visualizations'
16
+ import type { Chart, XAxis, YAxis, XAxisForm, ChartForApi } from '../../types/visualizations'
18
17
  import { useTranslation } from '../../composables/useTranslation'
19
18
 
20
19
  use([CanvasRenderer, LineChart, BarChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent, DatasetComponent])
@@ -23,26 +22,17 @@ const props = defineProps<{
23
22
  chart: Chart | ChartForApi
24
23
  series: {
25
24
  data: Record<string, Array<Record<string, unknown>>>
26
- columns: ColumnsDefinition
25
+ columns: Record<string, Array<{ name: string, type: string }>>
27
26
  }
28
27
  }>()
29
28
 
30
29
  const { locale } = useTranslation()
31
- const { formatDate } = useFormatDate()
32
30
  const chartContainer = ref<HTMLElement | null>(null)
33
31
  let echartsInstance: EChartsType | null = null
34
32
 
35
- function capture(): string | null {
36
- return echartsInstance?.getDataURL() ?? null
37
- }
38
-
39
- defineExpose({ capture })
40
-
41
- // ECharts has a dedicated 'time' axis type for continuous date values.
42
- function mapXAxisType(xAxis: XAxis | XAxisForm): 'category' | 'value' | 'time' {
33
+ function mapXAxisType(xAxis: XAxis | XAxisForm): 'category' | 'value' {
43
34
  if (!xAxis) return 'category'
44
- if (xAxis.type !== 'continuous') return 'category'
45
- return isDateAxis.value ? 'time' : 'value'
35
+ return xAxis.type === 'continuous' ? 'value' : 'category'
46
36
  }
47
37
 
48
38
  function buildYAxisFormatter(yAxis: YAxis): ((value: number) => string) | undefined {
@@ -54,77 +44,6 @@ function buildYAxisFormatter(yAxis: YAxis): ((value: number) => string) | undefi
54
44
  }
55
45
  }
56
46
 
57
- function buildXAxisFormatter(column: ColumnDefinition | null, options?: Intl.DateTimeFormatOptions): ((value: string | number | Date) => string) | undefined {
58
- if (column?.type !== 'date') return undefined
59
- return (value: string | number | Date) => {
60
- if (value === null || value === undefined) return ''
61
- const date = value instanceof Date ? value : new Date(value)
62
- if (Number.isNaN(date.getTime())) return String(value)
63
- return formatDate(date, options ?? { dateStyle: 'short' })
64
- }
65
- }
66
-
67
- function parseXValueAsDate(row: Record<string, unknown>, xColumn: string): Record<string, unknown> {
68
- const value = row[xColumn]
69
- if (value === null || value === undefined || value instanceof Date) return row
70
- if (typeof value === 'string') {
71
- const date = new Date(value)
72
- if (!Number.isNaN(date.getTime())) {
73
- return { ...row, [xColumn]: date }
74
- }
75
- }
76
- return row
77
- }
78
-
79
- const xAxisColumn = computed(() => {
80
- const columnName = props.chart.x_axis.column_x
81
- if (!columnName) return null
82
- for (const columns of Object.values(props.series.columns)) {
83
- const column = columns.find(c => c.name === columnName)
84
- if (column) return column
85
- }
86
- return null
87
- })
88
-
89
- const isDateAxis = computed(() => xAxisColumn.value?.type === 'date')
90
-
91
- const xAxisBounds = computed(() => {
92
- const columnName = props.chart.x_axis.column_x
93
- if (!columnName) return { min: undefined, max: undefined }
94
-
95
- let min: number | undefined
96
- let max: number | undefined
97
-
98
- for (const s of props.chart.series) {
99
- const xColumn = s.column_x_name_override ?? columnName
100
- const data = props.series.data[s.resource_id]
101
- if (!data) continue
102
-
103
- for (const row of data) {
104
- const value = row[xColumn]
105
- if (value === null || value === undefined) continue
106
-
107
- let numericValue: number | undefined
108
- if (value instanceof Date) {
109
- numericValue = value.getTime()
110
- }
111
- else if (isDateAxis.value && typeof value === 'string') {
112
- numericValue = new Date(value).getTime()
113
- }
114
- else {
115
- numericValue = Number(value)
116
- }
117
-
118
- if (numericValue === undefined || Number.isNaN(numericValue)) continue
119
-
120
- if (min === undefined || numericValue < min) min = numericValue
121
- if (max === undefined || numericValue > max) max = numericValue
122
- }
123
- }
124
-
125
- return { min, max }
126
- })
127
-
128
47
  const echartsOption = computed(() => {
129
48
  const seriesCount = props.chart.series.length
130
49
  if (!props.chart.series || seriesCount === 0) return
@@ -139,15 +58,12 @@ const echartsOption = computed(() => {
139
58
  return null
140
59
  }
141
60
 
142
- const rawData = props.series.data[resourceId]
143
- const sortedData = isDateAxis.value
144
- ? rawData.map(row => parseXValueAsDate(row, xColumn))
145
- : [...rawData]
146
- const sortBy = props.chart.x_axis.sort_x_by ?? (isDateAxis.value ? 'axis_x' : null)
61
+ const sortedData = [...props.series.data[resourceId]]
62
+ const sortBy = props.chart.x_axis.sort_x_by
147
63
  const sortDirection = props.chart.x_axis.sort_x_direction ?? 'asc'
148
64
 
149
65
  if (sortBy && sortDirection && props.chart.x_axis.column_x) {
150
- const sortKey = sortBy === 'axis_y' ? yColumn : xColumn
66
+ const sortKey = sortBy === 'axis_x' ? xColumn : yColumn
151
67
  sortedData.sort((a, b) => {
152
68
  const valA = a[sortKey]
153
69
  const valB = b[sortKey]
@@ -220,8 +136,6 @@ const echartsOption = computed(() => {
220
136
  seriesData.data.push(curr.data)
221
137
  }
222
138
 
223
- const xAxisType = mapXAxisType(props.chart.x_axis)
224
-
225
139
  return {
226
140
  dataset: [...seriesData.data],
227
141
  textStyle: {
@@ -232,12 +146,10 @@ const echartsOption = computed(() => {
232
146
  trigger: 'axis' as const,
233
147
  formatter: (params: Array<{ value: Record<string, unknown>, axisValueLabel: string, seriesName: string }>) => {
234
148
  let tooltip = ''
235
- const valueFormatter = new Intl.NumberFormat(locale)
236
- const xAxisFormatter = buildXAxisFormatter(xAxisColumn.value, { dateStyle: 'medium' })
149
+ const formatter = new Intl.NumberFormat('fr-FR')
237
150
  for (const param of params) {
238
151
  const seriesName = param.seriesName
239
- const axisLabel = xAxisFormatter ? xAxisFormatter(param.axisValueLabel) : param.axisValueLabel
240
- tooltip += `${format.encodeHTML(String(axisLabel))}: <strong>${valueFormatter.format(Number(param.value[seriesName]))}</strong><br>`
152
+ tooltip += `${format.encodeHTML(param.axisValueLabel)}: <strong>${formatter.format(Number(param.value[seriesName]))}</strong><br>`
241
153
  }
242
154
  return tooltip
243
155
  },
@@ -254,13 +166,8 @@ const echartsOption = computed(() => {
254
166
  containLabel: true,
255
167
  },
256
168
  xAxis: {
257
- type: xAxisType,
169
+ type: mapXAxisType(props.chart.x_axis),
258
170
  name: (props.chart.x_axis as XAxis).column_x,
259
- min: xAxisType !== 'category' ? xAxisColumn.value?.min ?? xAxisBounds.value.min ?? undefined : undefined,
260
- max: xAxisType !== 'category' ? xAxisColumn.value?.max ?? xAxisBounds.value.max ?? undefined : undefined,
261
- axisLabel: xAxisType === 'time'
262
- ? { formatter: buildXAxisFormatter(xAxisColumn.value) }
263
- : undefined,
264
171
  },
265
172
  yAxis: {
266
173
  type: 'value' as const,
@@ -5,7 +5,6 @@
5
5
  >
6
6
  <template #default="{ data }">
7
7
  <ChartViewer
8
- ref="chartViewerRef"
9
8
  :chart="chart"
10
9
  :series="data"
11
10
  />
@@ -34,13 +33,6 @@ const props = defineProps<{
34
33
  }>()
35
34
 
36
35
  const { t } = useTranslation()
37
- const chartViewerRef = ref<InstanceType<typeof ChartViewer> | null>(null)
38
-
39
- function capture(): string | null {
40
- return chartViewerRef.value?.capture() ?? null
41
- }
42
-
43
- defineExpose({ capture })
44
36
  const config = useComponentsConfig()
45
37
  const getProfile = useGetProfile()
46
38
 
@@ -99,11 +99,6 @@
99
99
  </p>
100
100
  </div>
101
101
  </div>
102
- <DataserviceQualityInline
103
- v-if="dataservice.quality"
104
- :quality="dataservice.quality"
105
- />
106
-
107
102
  <ObjectCardShortDescription
108
103
  v-if="showDescription"
109
104
  :text="dataservice.description"
@@ -131,7 +126,6 @@ import ObjectCardBadge from './ObjectCardBadge.vue'
131
126
  import ObjectCardHeader from './ObjectCardHeader.vue'
132
127
  import ObjectCardOwner from './ObjectCardOwner.vue'
133
128
  import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
134
- import DataserviceQualityInline from './DataserviceQualityInline.vue'
135
129
 
136
130
  type Props = {
137
131
  dataservice: Dataservice
@@ -13,7 +13,7 @@
13
13
  {{ t('Qualité des métadonnées:') }}
14
14
  </span>
15
15
  </span>
16
- <QualityScore
16
+ <DatasetQualityScore
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
- <QualityItemWarning
26
+ <DatasetQualityItemWarning
27
27
  :quality-item="quality.dataset_description_quality"
28
28
  :message="t('Description des données non renseignée')"
29
29
  />
30
- <QualityItemWarning
30
+ <DatasetQualityItemWarning
31
31
  :quality-item="quality.resources_documentation"
32
32
  :message="t('Documentation des fichiers manquante')"
33
33
  />
34
- <QualityItemWarning
34
+ <DatasetQualityItemWarning
35
35
  :quality-item="quality.license"
36
36
  :message="t('Licence non renseignée')"
37
37
  />
38
- <QualityItemWarning
38
+ <DatasetQualityItemWarning
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
- <QualityItemWarning
42
+ <DatasetQualityItemWarning
43
43
  :quality-item="quality.has_open_format"
44
44
  :message="t('Formats de fichiers non standards')"
45
45
  />
46
- <QualityItemWarning
46
+ <DatasetQualityItemWarning
47
47
  :quality-item="quality.temporal_coverage"
48
48
  :message="t('Couverture temporelle non renseignée')"
49
49
  />
50
- <QualityItemWarning
50
+ <DatasetQualityItemWarning
51
51
  :quality-item="quality.spatial"
52
52
  :message="t('Couverture spatiale non renseignée')"
53
53
  />
54
- <QualityItemWarning
54
+ <DatasetQualityItemWarning
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 QualityItemWarning from './QualityItemWarning.vue'
66
- import QualityScore from './QualityScore.vue'
65
+ import DatasetQualityItemWarning from './DatasetQualityItemWarning.vue'
66
+ import DatasetQualityScore from './DatasetQualityScore.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
- <QualityScore :score="quality.score" />
10
+ <DatasetQualityScore :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 QualityScore from './QualityScore.vue'
21
+ import DatasetQualityScore from './DatasetQualityScore.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 './QualityItem.vue'
71
+ import DatasetQualityItem from './DatasetQualityItem.vue'
72
72
 
73
73
  defineProps<{
74
74
  quality: Quality
@@ -224,10 +224,6 @@
224
224
  v-else-if="resource.format && resource.format.toLowerCase() === 'xml'"
225
225
  :resource="resource"
226
226
  />
227
- <ImagePreview
228
- v-else-if="isImagePreviewFormat(resource.format)"
229
- :resource="resource"
230
- />
231
227
  <!-- Show Datafair embedded preview (koumoul) -->
232
228
  <DatafairPreview
233
229
  v-else-if="hasDatafairPreview"
@@ -313,7 +309,7 @@ import { trackEvent } from '../../functions/matomo'
313
309
  import CopyButton from '../CopyButton.vue'
314
310
  import { useComponentsConfig } from '../../config'
315
311
  import { getOwnerName } from '../../functions/owned'
316
- import { getResourceFormatIcon, getResourceTitleId, detectOgcService, getResourceExternalUrl, getResourceFilesize, isImagePreviewFormat } from '../../functions/resources'
312
+ import { getResourceFormatIcon, getResourceTitleId, detectOgcService, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
317
313
  import BrandedButton from '../BrandedButton.vue'
318
314
  import { useTranslation } from '../../composables/useTranslation'
319
315
  import { useHasTabularData } from '../../composables/useHasTabularData'
@@ -348,7 +344,6 @@ const Pmtiles = defineAsyncComponent(() => import('./Pmtiles.client.vue'))
348
344
  const JsonPreview = defineAsyncComponent(() => import('./JsonPreview.client.vue'))
349
345
  const PdfPreview = defineAsyncComponent(() => import('./PdfPreview.client.vue'))
350
346
  const XmlPreview = defineAsyncComponent(() => import('./XmlPreview.client.vue'))
351
- const ImagePreview = defineAsyncComponent(() => import('./ImagePreview.client.vue'))
352
347
  const DatafairPreview = defineAsyncComponent(() => import('./Datafair.client.vue'))
353
348
 
354
349
  const { t } = useTranslation()
@@ -356,11 +351,11 @@ const { formatRelativeIfRecentDate } = useFormatDate()
356
351
  const checkTabularData = useHasTabularData()
357
352
 
358
353
  const hasPreview = computed(() => {
359
- // For JSON, PDF, XML, and image files, show preview.
354
+ // For JSON, PDF, and XML files, show preview.
360
355
  // We cannot check for CORS issues here because we cannot use an async component here.
361
356
  // If there is a CORS issue when fetching the file for preview, it will be managed and displayed as an error banner by the preview component.
362
357
  const format = props.resource.format?.toLowerCase()
363
- return format === 'json' || format === 'pdf' || format === 'xml' || isImagePreviewFormat(format)
358
+ return format === 'json' || format === 'pdf' || format === 'xml'
364
359
  })
365
360
 
366
361
  const hasTabularData = computed(() => checkTabularData(props.resource))
@@ -122,11 +122,6 @@
122
122
  v-if="ogcWms"
123
123
  :resource="resource"
124
124
  />
125
- <PreviewUnavailable v-if="!hasPmtiles && !ogcWms && hasPmtilesError">
126
- {{ t("La carte n'a pas pu être générée automatiquement pour ce fichier.") }}
127
- <br>
128
- <span class="text-gray-medium text-xs">{{ pmtilesError }}</span>
129
- </PreviewUnavailable>
130
125
  </div>
131
126
  <div v-if="tab.key === 'data'">
132
127
  <JsonPreview
@@ -141,10 +136,6 @@
141
136
  v-else-if="resource.format && resource.format.toLowerCase() === 'xml'"
142
137
  :resource="resource"
143
138
  />
144
- <ImagePreview
145
- v-else-if="isImagePreviewFormat(resource.format)"
146
- :resource="resource"
147
- />
148
139
  <DatafairPreview
149
140
  v-else-if="hasDatafairPreview"
150
141
  :resource="resource"
@@ -238,7 +229,7 @@ import Metadata from '../ResourceAccordion/Metadata.vue'
238
229
  import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
239
230
  import ResourceSelector from './ResourceSelector.vue'
240
231
  import { filesize, summarize } from '../../functions/helpers'
241
- import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize, isImagePreviewFormat } from '../../functions/resources'
232
+ import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
242
233
  import { trackEvent } from '../../functions/matomo'
243
234
  import { useComponentsConfig } from '../../config'
244
235
  import { useFormatDate } from '../../functions/dates'
@@ -257,9 +248,6 @@ const PdfPreview = defineAsyncComponent(() =>
257
248
  const XmlPreview = defineAsyncComponent(() =>
258
249
  import('../ResourceAccordion/XmlPreview.client.vue'),
259
250
  )
260
- const ImagePreview = defineAsyncComponent(() =>
261
- import('../ResourceAccordion/ImagePreview.client.vue'),
262
- )
263
251
  const DatafairPreview = defineAsyncComponent(() =>
264
252
  import('../ResourceAccordion/Datafair.client.vue'),
265
253
  )
@@ -287,8 +275,6 @@ const { formatRelativeIfRecentDate } = useFormatDate()
287
275
  const {
288
276
  hasTabularData,
289
277
  hasPmtiles,
290
- hasPmtilesError,
291
- pmtilesError,
292
278
  hasDatafairPreview,
293
279
  hasOpenAPIPreview,
294
280
  ogcService,
@@ -68,7 +68,7 @@ import { RiLockLine, RiSubtractLine } from '@remixicon/vue'
68
68
  import { computed } from 'vue'
69
69
  import type { RouteLocationRaw } from 'vue-router'
70
70
  import { useFormatDate } from '../functions/dates'
71
- import type { Reuse, ReuseV2 } from '../types/reuses'
71
+ import type { Reuse } from '../types/reuses'
72
72
  import type { TitleTag } from '../types/ui'
73
73
  import { useTranslation } from '../composables/useTranslation'
74
74
  import AppLink from './AppLink.vue'
@@ -77,7 +77,7 @@ import ReuseDetails from './ReuseDetails.vue'
77
77
  import Placeholder from './Placeholder.vue'
78
78
 
79
79
  const props = withDefaults(defineProps<{
80
- reuse: Reuse | ReuseV2
80
+ reuse: Reuse
81
81
 
82
82
  /**
83
83
  * The reuseUrl is a route location object to allow Vue Router to navigate to the details of a reuse.
@@ -32,11 +32,11 @@
32
32
  import { RiEyeLine, RiStarLine, RiSubtractLine } from '@remixicon/vue'
33
33
  import { useReuseType } from '../composables/useReuseType'
34
34
  import { summarize } from '../functions/helpers'
35
- import type { Reuse, ReuseV2 } from '../types/reuses'
35
+ import type { Reuse } from '../types/reuses'
36
36
  import { useTranslation } from '../composables/useTranslation'
37
37
 
38
38
  const props = defineProps<{
39
- reuse: Reuse | ReuseV2
39
+ reuse: Reuse
40
40
  }>()
41
41
 
42
42
  const { t } = useTranslation()
@@ -60,7 +60,7 @@
60
60
  <script setup lang="ts">
61
61
  import { RiArchiveLine, RiLineChartLine, RiLockLine } from '@remixicon/vue'
62
62
  import type { RouteLocationRaw } from 'vue-router'
63
- import type { Reuse, ReuseV2 } from '../types/reuses'
63
+ import type { Reuse } from '../types/reuses'
64
64
  import { useTranslation } from '../composables/useTranslation'
65
65
  import ReuseDetails from './ReuseDetails.vue'
66
66
  import Placeholder from './Placeholder.vue'
@@ -71,7 +71,7 @@ import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
71
71
  import ObjectCardBadge from './ObjectCardBadge.vue'
72
72
 
73
73
  defineProps<{
74
- reuse: Reuse | ReuseV2
74
+ reuse: Reuse
75
75
  reuseUrl?: RouteLocationRaw
76
76
  organizationUrl?: RouteLocationRaw
77
77
  }>()
@@ -266,7 +266,7 @@
266
266
  name="reuse"
267
267
  :reuse="result"
268
268
  >
269
- <ReuseHorizontalCard :reuse="(result as ReuseV2)" />
269
+ <ReuseHorizontalCard :reuse="(result as Reuse)" />
270
270
  </slot>
271
271
  </template>
272
272
  <template v-else-if="currentTypeConfig?.class === 'organizations'">
@@ -368,7 +368,7 @@ import type { AsyncDataRequestStatus } from '../../functions/api.types'
368
368
  import type { Dataset } from '../../types/datasets'
369
369
  import type { Dataservice } from '../../types/dataservices'
370
370
  import type { Organization } from '../../types/organizations'
371
- import type { ReuseV2 } from '../../types/reuses'
371
+ import type { Reuse } from '../../types/reuses'
372
372
  import type { TopicV2 } from '../../types/topics'
373
373
  import type { GlobalSearchConfig, SearchResponseByClass, SearchType, SortOption, FacetItem } from '../../types/search'
374
374
  import { getDefaultGlobalSearchConfig } from '../../types/search'
@@ -597,7 +597,6 @@
597
597
  <script setup lang="ts">
598
598
  import { computed, nextTick, onUnmounted, ref, watch, useTemplateRef } from 'vue'
599
599
  import { ofetch } from 'ofetch'
600
- import { useElementSize } from '@vueuse/core'
601
600
  import { flip, shift, autoUpdate, useFloating } from '@floating-ui/vue'
602
601
  import { Dialog, DialogPanel, DialogTitle, Popover, PopoverButton, PopoverPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'
603
602
  import {
@@ -833,43 +832,18 @@ function redistributeColumnWidths() {
833
832
  columnWidths.value = widths
834
833
  }
835
834
 
836
- // Measure the natural widths once (the <th> must still be auto-sized) and
837
- // distribute them. No-op once measured or while no column is displayed.
838
- function ensureMeasured() {
839
- if (Object.keys(naturalWidths.value).length > 0) return
840
- if (displayedColumns.value.length === 0) return
841
- measureNaturalWidths()
842
- redistributeColumnWidths()
843
- }
844
-
845
- // Drive measurement and re-stretch off the container's reactive width
846
- // (`useElementSize` wraps a ResizeObserver and disconnects it on unmount). The
847
- // width goes 0 -> N once the table is laid out in the DOM, which is also when
848
- // the <thead> carries its content-driven natural widths: the first non-zero
849
- // width measures the stable base, later changes (window resize) only
850
- // redistribute it.
851
- const { width: containerWidth } = useElementSize(scrollContainerRef)
852
-
853
- watch(containerWidth, (width) => {
854
- if (width === 0) return
855
- if (Object.keys(naturalWidths.value).length === 0) {
856
- ensureMeasured()
857
- }
858
- else {
859
- redistributeColumnWidths()
860
- }
861
- })
862
-
863
- // Fallback: re-run once columns appear if they weren't available when the
864
- // container was first sized (standalone usage where the profile resolves late).
835
+ // Measure once both data and profile are ready (so the <thead> is rendered with
836
+ // content-driven natural widths), then distribute.
865
837
  watch(
866
838
  () => [tableData.value !== null, displayedColumns.value.length] as const,
867
839
  async ([dataReady, colCount]) => {
868
840
  if (!dataReady || colCount === 0) return
869
841
  if (Object.keys(naturalWidths.value).length > 0) return
870
842
  await nextTick()
871
- ensureMeasured()
843
+ measureNaturalWidths()
844
+ redistributeColumnWidths()
872
845
  },
846
+ { immediate: true },
873
847
  )
874
848
 
875
849
  // Re-stretch the remaining columns whenever the displayed set changes (columns
@@ -51,8 +51,8 @@ export type TabularColumnProfile = {
51
51
  tops: TabularTopValue[]
52
52
  nb_distinct: number
53
53
  nb_missing_values: number
54
- min?: number | string
55
- max?: number | string
54
+ min?: number
55
+ max?: number
56
56
  std?: number
57
57
  mean?: number
58
58
  }
@@ -1,5 +1,4 @@
1
1
  import { useComponentsConfig } from '../config'
2
- import { hasTabularParsingError } from '../functions/resources'
3
2
  import type { Resource } from '../types/resources'
4
3
 
5
4
  /**
@@ -21,7 +20,7 @@ export const useHasTabularData = () => {
21
20
  return (
22
21
  config.tabularApiUrl
23
22
  && resource.extras['analysis:parsing:parsing_table']
24
- && !hasTabularParsingError(resource)
23
+ && !resource.extras['analysis:parsing:error']
25
24
  && !sourceUnreachable
26
25
  && (config.tabularAllowRemote || resource.filetype === 'file')
27
26
  )