@datagouv/components-next 1.0.2-dev.156 → 1.0.2-dev.157

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 (22) hide show
  1. package/dist/{Datafair.client-bp15NLRY.js → Datafair.client-Bblv8Xec.js} +1 -1
  2. package/dist/ImagePreview.client-B9p_XZrx.js +36 -0
  3. package/dist/{JsonPreview.client-yqVpZTmF.js → JsonPreview.client-DzVXqgqm.js} +2 -2
  4. package/dist/{MapContainer.client-2lywLnVm.js → MapContainer.client-JFOchs0n.js} +2 -2
  5. package/dist/{PdfPreview.client-BG7MXWMB.js → PdfPreview.client-De6XYp-a.js} +2 -2
  6. package/dist/{Pmtiles.client-5ghpJ7mq.js → Pmtiles.client-CiLdMaAj.js} +1 -1
  7. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-C-sK1BJV.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-keE4Kr1e.js} +1 -1
  8. package/dist/{XmlPreview.client-DWzKxXoL.js → XmlPreview.client-CdxaPXOa.js} +3 -3
  9. package/dist/components-next.css +1 -1
  10. package/dist/components-next.js +50 -49
  11. package/dist/components.css +1 -1
  12. package/dist/{index-B6iEXWF6.js → index-BIk8VKNQ.js} +1 -1
  13. package/dist/{leaflet-src-CpoKI-p2.js → leaflet-src-B_fapURG.js} +1 -1
  14. package/dist/{main-uIKdSuDJ.js → main-B0TVT1sb.js} +8262 -8249
  15. package/dist/{vue3-xml-viewer.common-C2hQ2aXh.js → vue3-xml-viewer.common-Bx0jB4Yr.js} +1 -1
  16. package/package.json +1 -1
  17. package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
  18. package/src/components/ResourceAccordion/ResourceAccordion.vue +8 -3
  19. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +8 -1
  20. package/src/composables/useResourceCapabilities.ts +7 -7
  21. package/src/config.ts +1 -0
  22. package/src/functions/resources.ts +7 -0
@@ -1,4 +1,4 @@
1
- import { g as Ke } from "./main-uIKdSuDJ.js";
1
+ import { g as Ke } from "./main-B0TVT1sb.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.156",
3
+ "version": "1.0.2-dev.157",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <div class="text-xs">
3
+ <PreviewUnavailable v-if="!isSizeAllowed">
4
+ {{ fileSizeBytes
5
+ ? t("Le fichier {fileType} est trop volumineux pour être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.", { fileType })
6
+ : t("La taille du fichier est inconnue, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.")
7
+ }}
8
+ </PreviewUnavailable>
9
+ <PreviewUnavailable v-else-if="hasError">
10
+ {{ t("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.") }}
11
+ </PreviewUnavailable>
12
+ <img
13
+ v-else
14
+ :src="resource.url"
15
+ alt=""
16
+ class="block w-full h-auto max-w-[800px]"
17
+ @error="hasError = true"
18
+ >
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed, ref } from 'vue'
24
+ import PreviewUnavailable from './PreviewUnavailable.vue'
25
+ import type { Resource } from '../../types/resources'
26
+ import { getResourceFilesize } from '../../functions/resources'
27
+ import { useTranslation } from '../../composables/useTranslation'
28
+ import { useComponentsConfig } from '../../config'
29
+
30
+ const props = defineProps<{
31
+ resource: Resource
32
+ }>()
33
+
34
+ const { t } = useTranslation()
35
+ const config = useComponentsConfig()
36
+
37
+ const hasError = ref(false)
38
+
39
+ const fileType = computed(() => props.resource.format?.toUpperCase() ?? t('Fichier'))
40
+ const fileSizeBytes = computed(() => getResourceFilesize(props.resource))
41
+
42
+ const isSizeAllowed = computed(() => {
43
+ const size = fileSizeBytes.value
44
+ const max = config.maxImagePreviewByteSize
45
+ if (!size || !max) return false
46
+ return size <= max
47
+ })
48
+ </script>
@@ -224,6 +224,10 @@
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
+ />
227
231
  <!-- Show Datafair embedded preview (koumoul) -->
228
232
  <DatafairPreview
229
233
  v-else-if="hasDatafairPreview"
@@ -309,7 +313,7 @@ import { trackEvent } from '../../functions/matomo'
309
313
  import CopyButton from '../CopyButton.vue'
310
314
  import { useComponentsConfig } from '../../config'
311
315
  import { getOwnerName } from '../../functions/owned'
312
- import { getResourceFormatIcon, getResourceTitleId, detectOgcService, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
316
+ import { getResourceFormatIcon, getResourceTitleId, detectOgcService, getResourceExternalUrl, getResourceFilesize, isImagePreviewFormat } from '../../functions/resources'
313
317
  import BrandedButton from '../BrandedButton.vue'
314
318
  import { useTranslation } from '../../composables/useTranslation'
315
319
  import { useHasTabularData } from '../../composables/useHasTabularData'
@@ -344,6 +348,7 @@ const Pmtiles = defineAsyncComponent(() => import('./Pmtiles.client.vue'))
344
348
  const JsonPreview = defineAsyncComponent(() => import('./JsonPreview.client.vue'))
345
349
  const PdfPreview = defineAsyncComponent(() => import('./PdfPreview.client.vue'))
346
350
  const XmlPreview = defineAsyncComponent(() => import('./XmlPreview.client.vue'))
351
+ const ImagePreview = defineAsyncComponent(() => import('./ImagePreview.client.vue'))
347
352
  const DatafairPreview = defineAsyncComponent(() => import('./Datafair.client.vue'))
348
353
 
349
354
  const { t } = useTranslation()
@@ -351,11 +356,11 @@ const { formatRelativeIfRecentDate } = useFormatDate()
351
356
  const checkTabularData = useHasTabularData()
352
357
 
353
358
  const hasPreview = computed(() => {
354
- // For JSON, PDF, and XML files, show preview.
359
+ // For JSON, PDF, XML, and image files, show preview.
355
360
  // We cannot check for CORS issues here because we cannot use an async component here.
356
361
  // 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.
357
362
  const format = props.resource.format?.toLowerCase()
358
- return format === 'json' || format === 'pdf' || format === 'xml'
363
+ return format === 'json' || format === 'pdf' || format === 'xml' || isImagePreviewFormat(format)
359
364
  })
360
365
 
361
366
  const hasTabularData = computed(() => checkTabularData(props.resource))
@@ -141,6 +141,10 @@
141
141
  v-else-if="resource.format && resource.format.toLowerCase() === 'xml'"
142
142
  :resource="resource"
143
143
  />
144
+ <ImagePreview
145
+ v-else-if="isImagePreviewFormat(resource.format)"
146
+ :resource="resource"
147
+ />
144
148
  <DatafairPreview
145
149
  v-else-if="hasDatafairPreview"
146
150
  :resource="resource"
@@ -234,7 +238,7 @@ import Metadata from '../ResourceAccordion/Metadata.vue'
234
238
  import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
235
239
  import ResourceSelector from './ResourceSelector.vue'
236
240
  import { filesize, summarize } from '../../functions/helpers'
237
- import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
241
+ import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize, isImagePreviewFormat } from '../../functions/resources'
238
242
  import { trackEvent } from '../../functions/matomo'
239
243
  import { useComponentsConfig } from '../../config'
240
244
  import { useFormatDate } from '../../functions/dates'
@@ -253,6 +257,9 @@ const PdfPreview = defineAsyncComponent(() =>
253
257
  const XmlPreview = defineAsyncComponent(() =>
254
258
  import('../ResourceAccordion/XmlPreview.client.vue'),
255
259
  )
260
+ const ImagePreview = defineAsyncComponent(() =>
261
+ import('../ResourceAccordion/ImagePreview.client.vue'),
262
+ )
256
263
  const DatafairPreview = defineAsyncComponent(() =>
257
264
  import('../ResourceAccordion/Datafair.client.vue'),
258
265
  )
@@ -1,12 +1,12 @@
1
- import { computed, toValue, type MaybeRefOrGetter } from 'vue'
1
+ import { computed, type MaybeRefOrGetter, toValue } from 'vue'
2
2
  import { useComponentsConfig } from '../config'
3
- import { useTranslation } from './useTranslation'
4
- import { useHasTabularData } from './useHasTabularData'
5
- import { detectOgcService, getParsingErrorMessage, getParsingErrorStep } from '../functions/resources'
6
3
  import { isOrganizationCertified } from '../functions/organizations'
7
- import type { Resource, WfsMetadata } from '../types/resources'
8
- import type { Dataset, DatasetV2 } from '../types/datasets'
9
4
  import { getWfsExportFormats } from '../functions/resourceCapabilities'
5
+ import { detectOgcService, getParsingErrorMessage, getParsingErrorStep, isImagePreviewFormat } from '../functions/resources'
6
+ import type { Dataset, DatasetV2 } from '../types/datasets'
7
+ import type { Resource, WfsMetadata } from '../types/resources'
8
+ import { useHasTabularData } from './useHasTabularData'
9
+ import { useTranslation } from './useTranslation'
10
10
 
11
11
  const GENERATED_FORMATS = ['parquet', 'pmtiles', 'geojson']
12
12
  const URL_FORMATS = ['url', 'doi', 'www:link', 'www:link-1.0-http--link', 'www:link-1.0-http--partners', 'www:link-1.0-http--related', 'www:link-1.0-http--samples']
@@ -21,7 +21,7 @@ export function useResourceCapabilities(
21
21
 
22
22
  const hasPreview = computed(() => {
23
23
  const format = toValue(resource).format?.toLowerCase()
24
- return format === 'json' || format === 'pdf' || format === 'xml'
24
+ return format === 'json' || format === 'pdf' || format === 'xml' || isImagePreviewFormat(format)
25
25
  })
26
26
 
27
27
  const hasTabularData = computed(() => {
package/src/config.ts CHANGED
@@ -12,6 +12,7 @@ export type PluginConfig = {
12
12
  datasetQualityGuideUrl?: string
13
13
  maxJsonPreviewCharSize?: number // Maximum size of JSON to preview in characters. JSON preview module is partly collapsed by default so we can have a preview for large files.
14
14
  maxPdfPreviewByteSize?: number // Maximum size of PDF to preview in bytes
15
+ maxImagePreviewByteSize?: number // Maximum size of image to preview in bytes
15
16
  maxXmlPreviewCharSize?: number // Maximum size of XML to preview in characters. XML preview module can NOT be collapsed by default so we should not have a preview for large files.
16
17
  pmtilesViewerBaseUrl?: string | null // Base URL of a pmtiles viewer (ex: https://pmtiles.io/#url=)
17
18
  metricsApiUrl?: string
@@ -167,6 +167,13 @@ export function getResourceFilesize(resource: Resource): null | number {
167
167
  return null
168
168
  }
169
169
 
170
+ const IMAGE_PREVIEW_FORMATS = ['png', 'jpg', 'jpeg', 'jpe', 'gif', 'webp'] as const
171
+
172
+ export function isImagePreviewFormat(format: string | undefined | null): boolean {
173
+ if (!format) return false
174
+ return IMAGE_PREVIEW_FORMATS.includes(format.toLowerCase() as typeof IMAGE_PREVIEW_FORMATS[number])
175
+ }
176
+
170
177
  // Parsing errors are stored as `<step>:<message>`, where `<step>` names the
171
178
  // analysis step that failed (e.g. `pmtiles_export`, `geojson_export`).
172
179