@datagouv/components-next 1.0.2-dev.4 → 1.0.2-dev.40

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 (52) hide show
  1. package/dist/Datafair.client-CYO9vwx6.js +30 -0
  2. package/dist/JsonPreview.client-B6aU3vl4.js +78 -0
  3. package/dist/{MapContainer.client-DjjvdKBp.js → MapContainer.client-BZsKgRUh.js} +35 -38
  4. package/dist/{PdfPreview.client-CsvKU0Aq.js → PdfPreview.client-ClkseuKU.js} +694 -700
  5. package/dist/{Pmtiles.client-uqg1fwOl.js → Pmtiles.client-CUaeaV-O.js} +574 -579
  6. package/dist/Swagger.client-FpYXdDuX.js +4 -0
  7. package/dist/XmlPreview.client-BNGHvVnU.js +70 -0
  8. package/dist/components-next.css +3 -3
  9. package/dist/components-next.js +83 -86
  10. package/dist/components.css +1 -1
  11. package/dist/{index-PMeuFwWj.js → index-B0fPq7-b.js} +1 -1
  12. package/dist/{main-ByqZlhiZ.js → main-ifX24DGW.js} +31224 -30474
  13. package/dist/{vue3-xml-viewer.common-DFrGHXJC.js → vue3-xml-viewer.common-Bkgr-tAS.js} +1 -1
  14. package/package.json +10 -8
  15. package/src/components/ActivityList/ActivityList.vue +0 -2
  16. package/src/components/Form/SearchableSelect.vue +2 -1
  17. package/src/components/Pagination.vue +8 -5
  18. package/src/components/ReadMore.vue +1 -1
  19. package/src/components/ResourceAccordion/Datafair.client.vue +4 -10
  20. package/src/components/ResourceAccordion/JsonPreview.client.vue +34 -47
  21. package/src/components/ResourceAccordion/MapContainer.client.vue +7 -11
  22. package/src/components/ResourceAccordion/Metadata.vue +1 -2
  23. package/src/components/ResourceAccordion/PdfPreview.client.vue +28 -32
  24. package/src/components/ResourceAccordion/Pmtiles.client.vue +5 -10
  25. package/src/components/ResourceAccordion/Preview.vue +6 -11
  26. package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
  27. package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
  28. package/src/components/ResourceAccordion/ResourceAccordion.vue +1 -2
  29. package/src/components/ResourceAccordion/XmlPreview.client.vue +34 -47
  30. package/src/components/ResourceExplorer/ResourceExplorer.vue +21 -10
  31. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +24 -3
  32. package/src/components/Search/GlobalSearch.vue +29 -4
  33. package/src/composables/useResourceCapabilities.ts +1 -1
  34. package/src/config.ts +2 -0
  35. package/src/functions/datasets.ts +0 -17
  36. package/src/functions/resources.ts +56 -1
  37. package/src/functions/tabularApi.ts +7 -84
  38. package/src/main.ts +2 -22
  39. package/src/types/dataservices.ts +2 -0
  40. package/src/types/organizations.ts +1 -1
  41. package/src/types/reports.ts +3 -0
  42. package/src/types/search.ts +26 -1
  43. package/src/types/users.ts +0 -1
  44. package/dist/Datafair.client-c1cUKkQR.js +0 -35
  45. package/dist/JsonPreview.client-CAs9XTCX.js +0 -87
  46. package/dist/Swagger.client-BGrkka3l.js +0 -4
  47. package/dist/XmlPreview.client-BWbKzLte.js +0 -79
  48. package/src/components/Chart/ChartViewer.vue +0 -152
  49. package/src/components/Chart/ChartViewerWrapper.vue +0 -194
  50. package/src/functions/pagination.ts +0 -9
  51. package/src/types/visualizations.ts +0 -84
  52. /package/assets/illustrations/{_microscope.svg → microscope.svg} +0 -0
@@ -1,4 +1,4 @@
1
- import { b as Ke } from "./main-ByqZlhiZ.js";
1
+ import { c as Ke } from "./main-ifX24DGW.js";
2
2
  import We from "vue";
3
3
  function Fe(I, 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.4",
3
+ "version": "1.0.2-dev.40",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -16,16 +16,15 @@
16
16
  "src"
17
17
  ],
18
18
  "dependencies": {
19
- "@floating-ui/vue": "^1.1.8",
19
+ "@floating-ui/vue": "^1.1.11",
20
20
  "@headlessui/vue": "^1.7.23",
21
21
  "@remixicon/vue": "^4.5.0",
22
22
  "@types/hast": "^3.0.4",
23
23
  "@types/leaflet": "^1.9.17",
24
- "@vueuse/core": "^13.1.0",
25
- "@vueuse/router": "^13.1.0",
24
+ "@vueuse/core": "^14.2.1",
25
+ "@vueuse/router": "^14.2.1",
26
26
  "chart.js": "^4.4.8",
27
27
  "dompurify": "^3.2.5",
28
- "echarts": "^6.0.0",
29
28
  "geopf-extensions-openlayers": "^1.0.0-beta.5",
30
29
  "leaflet": "^1.9.4",
31
30
  "maplibre-gl": "^5.6.2",
@@ -49,10 +48,7 @@
49
48
  "swagger-ui-dist": "^5.27.1",
50
49
  "unified": "^11.0.5",
51
50
  "unist-util-visit": "^5.0.0",
52
- "vue": "^3.5.13",
53
51
  "vue-content-loader": "^2.0.1",
54
- "vue-echarts": "^8.0.1",
55
- "vue-router": "^4.5.0",
56
52
  "vue-sonner": "^2.0.9",
57
53
  "vue3-json-viewer": "^2.4.1",
58
54
  "vue3-text-clamp": "^0.1.2",
@@ -78,8 +74,14 @@
78
74
  "typescript": "^5.7.3",
79
75
  "vite": "^7.0",
80
76
  "vite-plugin-vue-devtools": "^8.0",
77
+ "vue": "^3.5.31",
78
+ "vue-router": "^5.0.4",
81
79
  "vue-tsc": "^3.0"
82
80
  },
81
+ "peerDependencies": {
82
+ "vue": "^3.5.13",
83
+ "vue-router": "^4.5.0 || ^5.0.0"
84
+ },
83
85
  "scarfSettings": {
84
86
  "enabled": false
85
87
  },
@@ -90,7 +90,6 @@
90
90
  :total-results="activities.total"
91
91
  :page-size="activities.page_size"
92
92
  :page="activities.page"
93
- :link="getLink"
94
93
  @change="(newPage: number) => page = newPage"
95
94
  />
96
95
  </template>
@@ -117,7 +116,6 @@ import { useTranslation } from '../../composables/useTranslation'
117
116
  import { getActivityTranslation } from '../../functions/activities'
118
117
  import { useFetch } from '../../functions/api'
119
118
  import { useFormatDate } from '../../functions/dates'
120
- import { getLink } from '../../functions/pagination'
121
119
  import type { PaginatedArray } from '../../types/api'
122
120
  import type { Activity } from '../../types/activity'
123
121
  import Avatar from '../Avatar.vue'
@@ -10,8 +10,9 @@
10
10
  :class="{ 'sr-only': hideLabel }"
11
11
  >
12
12
  {{ label }}
13
+ <!-- $props needed: in generic components, vue-tsc resolves `required` to the Nuxt auto-imported function instead of the prop -->
13
14
  <span
14
- v-if="required"
15
+ v-if="$props.required"
15
16
  class="text-new-primary"
16
17
  >*</span>
17
18
  <span
@@ -101,6 +101,7 @@
101
101
 
102
102
  <script setup lang="ts">
103
103
  import { computed, useTemplateRef } from 'vue'
104
+ import { useRoute } from 'vue-router'
104
105
  import { useTranslation } from '../composables/useTranslation'
105
106
 
106
107
  type Props = {
@@ -112,10 +113,6 @@ type Props = {
112
113
  * The page size.
113
114
  */
114
115
  pageSize?: number
115
- /**
116
- * Customize the links used
117
- */
118
- link?: (page: number) => string
119
116
  /**
120
117
  * The number of items in the collection. It's used to calculated the number of pages.
121
118
  */
@@ -174,6 +171,7 @@ function getVisiblePages(currentPage: number, pageCount: number) {
174
171
  }
175
172
 
176
173
  const { t } = useTranslation()
174
+ const route = useRoute()
177
175
  const pageCount = computed(() => Math.ceil(props.totalResults / props.pageSize))
178
176
  const visiblePages = computed(() => getVisiblePages(props.page, pageCount.value))
179
177
 
@@ -211,6 +209,11 @@ function getHref(forPage: number) {
211
209
  if (forPage < 1 || forPage > pageCount.value) {
212
210
  return undefined
213
211
  }
214
- return props.page === forPage ? undefined : (props.link ? props.link(forPage) : '#')
212
+ if (props.page === forPage) {
213
+ return undefined
214
+ }
215
+ const search = new URLSearchParams(route.query as Record<string, string>)
216
+ search.set('page', forPage.toFixed(0))
217
+ return `${route.path}?${search.toString()}`
215
218
  }
216
219
  </script>
@@ -3,7 +3,7 @@
3
3
  <div
4
4
  ref="readMoreRef"
5
5
  class="overflow-hidden"
6
- :style="{ height: containerHeight + 'px' }"
6
+ :style="{ height: readMoreRequired ? containerHeight + 'px' : 'auto' }"
7
7
  >
8
8
  <div ref="containerRef">
9
9
  <slot />
@@ -9,21 +9,15 @@
9
9
  border: none;"
10
10
  />
11
11
  </div>
12
- <SimpleBanner
13
- v-else
14
- type="warning"
15
- class="flex items-center space-x-2"
16
- >
17
- <RiErrorWarningLine class="shrink-0 size-6" />
18
- <span>{{ t("Erreur lors de l'affichage de l'aperçu.") }}</span>
19
- </SimpleBanner>
12
+ <PreviewUnavailable v-else>
13
+ {{ t("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.") }}
14
+ </PreviewUnavailable>
20
15
  </div>
21
16
  </template>
22
17
 
23
18
  <script setup lang="ts">
24
19
  import { computed } from 'vue'
25
- import { RiErrorWarningLine } from '@remixicon/vue'
26
- import SimpleBanner from '../SimpleBanner.vue'
20
+ import PreviewUnavailable from './PreviewUnavailable.vue'
27
21
  import type { Resource } from '../../types/resources'
28
22
  import type { Dataset, DatasetV2 } from '../../types/datasets'
29
23
  import { useTranslation } from '../../composables/useTranslation'
@@ -17,45 +17,31 @@
17
17
  >
18
18
  {{ t("Chargement de l'aperçu JSON...") }}
19
19
  </div>
20
- <SimpleBanner
21
- v-else-if="fileTooLarge"
22
- type="warning"
23
- class="flex items-center space-x-2"
24
- >
25
- <RiErrorWarningLine class="shrink-0 size-6" />
26
- <span>{{ fileSizeBytes
27
- ? t("Fichier JSON trop volumineux pour l'aperçu. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
28
- : t("L'aperçu n'est pas disponible car la taille du fichier est inconnue. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
29
- }}</span>
30
- </SimpleBanner>
31
- <SimpleBanner
32
- v-else-if="error === 'network'"
33
- type="warning"
34
- class="flex items-center space-x-2"
35
- >
36
- <RiErrorWarningLine class="shrink-0 size-6" />
37
- <span>{{ t("Ce fichier JSON ne peut pas être prévisualisé, peut-être parce qu'il est hébergé sur un autre site qui ne l'autorise pas. Pour le consulter, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.") }}</span>
38
- </SimpleBanner>
39
- <SimpleBanner
40
- v-else-if="error"
41
- type="warning"
42
- class="flex items-center space-x-2"
43
- >
44
- <RiErrorWarningLine class="shrink-0 size-6" />
45
- <span>{{ t("Erreur lors du chargement de l'aperçu JSON.") }}</span>
46
- </SimpleBanner>
20
+ <PreviewUnavailable v-else-if="fileTooLarge">
21
+ {{ fileSizeBytes
22
+ ? t("Le fichier JSON est trop volumineux pour être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.")
23
+ : t("La taille du fichier est inconnue, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.")
24
+ }}
25
+ </PreviewUnavailable>
26
+ <PreviewUnavailable v-else-if="error === 'cors'">
27
+ {{ t("Ce fichier JSON ne peut pas être prévisualisé car il est hébergé sur un site distant qui restreint l'accès (CORS). Téléchargez-le depuis l'onglet Téléchargements.") }}
28
+ </PreviewUnavailable>
29
+ <PreviewUnavailable v-else-if="error === 'network'">
30
+ {{ t("Ce fichier est hébergé sur un site externe qui ne permet pas la prévisualisation. Téléchargez-le depuis l'onglet Téléchargements.") }}
31
+ </PreviewUnavailable>
32
+ <PreviewUnavailable v-else-if="error">
33
+ {{ t("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.") }}
34
+ </PreviewUnavailable>
47
35
  </div>
48
36
  </template>
49
37
 
50
38
  <script setup lang="ts">
51
39
  import { computed, defineAsyncComponent, onMounted, ref } from 'vue'
52
- import { RiErrorWarningLine } from '@remixicon/vue'
53
-
54
40
  import { useComponentsConfig } from '../../config'
55
- import SimpleBanner from '../SimpleBanner.vue'
41
+ import PreviewUnavailable from './PreviewUnavailable.vue'
56
42
  import type { Resource } from '../../types/resources'
43
+ import { getResourceFilesize, getResourceCorsStatus } from '../../functions/resources'
57
44
  import { useTranslation } from '../../composables/useTranslation'
58
- import { getResourceFilesize } from '../../functions/datasets'
59
45
 
60
46
  const JsonViewer = defineAsyncComponent(() =>
61
47
  import('vue3-json-viewer').then((module) => {
@@ -79,36 +65,37 @@ const fileTooLarge = ref(false)
79
65
 
80
66
  const fileSizeBytes = computed(() => getResourceFilesize(props.resource))
81
67
 
82
- const shouldLoadJson = computed(() => {
83
- const size = fileSizeBytes.value
84
- if (!size) {
85
- // If we don't know the size, don't risk loading a potentially huge file
86
- return false
87
- }
88
-
89
- // Check if maxJsonPreviewCharSize is configured
90
- if (!config.maxJsonPreviewCharSize) {
91
- // If no limit is set, don't load unknown files
92
- return false
93
- }
68
+ const corsStatus = computed(() => getResourceCorsStatus(props.resource))
94
69
 
70
+ const isSizeAllowed = computed(() => {
71
+ const size = fileSizeBytes.value
95
72
  // Convert maxJsonPreviewCharSize from characters to bytes (rough estimate)
96
73
  // Assuming average 1 byte per character for JSON
97
74
  const maxByteSize = config.maxJsonPreviewCharSize
98
75
 
76
+ // If we don't know the size or the max size, don't risk loading a potentially huge file
77
+ if (!size || !maxByteSize) return false
78
+
99
79
  return size <= maxByteSize
100
80
  })
101
81
 
102
82
  const fetchJsonData = async () => {
103
- // Check if file is too large or size is unknown before making the request
104
- if (!shouldLoadJson.value) {
83
+ error.value = null
84
+ fileTooLarge.value = false
85
+
86
+ // Check if file is too large or size is unknown
87
+ if (!isSizeAllowed.value) {
105
88
  fileTooLarge.value = true
106
89
  return
107
90
  }
108
91
 
109
- loading.value = true
110
- error.value = null
92
+ // Check if CORS is allowed
93
+ if (corsStatus.value === 'blocked') {
94
+ error.value = 'cors'
95
+ return
96
+ }
111
97
 
98
+ loading.value = true
112
99
  try {
113
100
  const response = await fetch(props.resource.url)
114
101
  // const response = await fetch('/test-data.json') // For testing locally without CORS issues
@@ -1,12 +1,7 @@
1
1
  <template>
2
- <SimpleBanner
3
- v-if="hasError"
4
- type="warning"
5
- class="flex items-center space-x-2"
6
- >
7
- <RiErrorWarningLine class="shrink-0 size-6" />
8
- <span>{{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}</span>
9
- </SimpleBanner>
2
+ <PreviewUnavailable v-if="hasError">
3
+ {{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}
4
+ </PreviewUnavailable>
10
5
  <div
11
6
  v-else
12
7
  id="map"
@@ -16,9 +11,7 @@
16
11
 
17
12
  <script setup lang = "ts">
18
13
  import { onMounted, ref, useTemplateRef } from 'vue'
19
- import { RiErrorWarningLine } from '@remixicon/vue'
20
-
21
- import SimpleBanner from '../SimpleBanner.vue'
14
+ import PreviewUnavailable from './PreviewUnavailable.vue'
22
15
  import type { Resource } from '../../types/resources'
23
16
  import { useTranslation } from '../../composables/useTranslation'
24
17
 
@@ -96,7 +89,10 @@ async function displayMap() {
96
89
 
97
90
  const attributions = new GeoportalAttribution({
98
91
  position: 'bottom-right',
92
+ // collapsed option is ignored by the library, thus the override below
93
+ // see https://github.com/IGNF/geopf-extensions-openlayers/issues/497
99
94
  })
95
+ attributions.setCollapsed(false)
100
96
  map.addControl(attributions)
101
97
 
102
98
  const layerImport = new LayerImport({
@@ -7,9 +7,8 @@ import DescriptionTerm from '../DescriptionTerm.vue'
7
7
  import { useFormatDate } from '../../functions/dates'
8
8
  import { filesize } from '../../functions/helpers'
9
9
  import ExtraAccordion from '../ExtraAccordion.vue'
10
- import { getResourceTitleId, getResourceLabel } from '../../functions/resources'
10
+ import { getResourceTitleId, getResourceLabel, getResourceFilesize } from '../../functions/resources'
11
11
  import { useTranslation } from '../../composables/useTranslation'
12
- import { getResourceFilesize } from '../../functions/datasets'
13
12
 
14
13
  const props = defineProps<{
15
14
  resource: Resource
@@ -18,47 +18,34 @@
18
18
  >
19
19
  {{ t("Chargement de l'aperçu PDF...") }}
20
20
  </div>
21
- <SimpleBanner
22
- v-else-if="fileTooLarge"
23
- type="warning"
24
- class="flex items-center space-x-2"
25
- >
26
- <RiErrorWarningLine class="flex-none size-6" />
27
- <span>{{ fileSizeBytes
28
- ? t("Fichier PDF trop volumineux pour l'aperçu. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
29
- : t("L'aperçu n'est pas disponible car la taille du fichier est inconnue. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
30
- }}</span>
31
- </SimpleBanner>
32
- <SimpleBanner
33
- v-else-if="error === 'network'"
34
- type="warning"
35
- class="flex items-center space-x-2"
36
- >
37
- <RiErrorWarningLine class="flex-none size-6" />
38
- <span>{{ t("Ce fichier PDF ne peut pas être prévisualisé, peut-être parce qu'il est hébergé sur un autre site qui ne l'autorise pas. Pour le consulter, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.") }}</span>
39
- </SimpleBanner>
40
- <SimpleBanner
41
- v-else-if="error"
42
- type="warning"
43
- class="flex items-center space-x-2"
44
- >
45
- <RiErrorWarningLine class="flex-none size-6" />
46
- <span>{{ t("Erreur lors du chargement de l'aperçu PDF. Pour consulter le fichier, téléchargez-le depuis l'onglet Téléchargements.") }}</span>
47
- </SimpleBanner>
21
+ <PreviewUnavailable v-else-if="fileTooLarge">
22
+ {{ fileSizeBytes
23
+ ? t("Le fichier PDF est trop volumineux pour être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.")
24
+ : t("La taille du fichier est inconnue, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.")
25
+ }}
26
+ </PreviewUnavailable>
27
+ <PreviewUnavailable v-else-if="error === 'cors'">
28
+ {{ t("Ce fichier PDF ne peut pas être prévisualisé car il est hébergé sur un site distant qui restreint l'accès (CORS). Téléchargez-le depuis l'onglet Téléchargements.") }}
29
+ </PreviewUnavailable>
30
+ <PreviewUnavailable v-else-if="error === 'network'">
31
+ {{ t("Ce fichier est hébergé sur un site externe qui ne permet pas la prévisualisation. Téléchargez-le depuis l'onglet Téléchargements.") }}
32
+ </PreviewUnavailable>
33
+ <PreviewUnavailable v-else-if="error">
34
+ {{ t("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.") }}
35
+ </PreviewUnavailable>
48
36
  </div>
49
37
  </template>
50
38
 
51
39
  <script setup lang="ts">
52
40
  import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
53
- import { RiErrorWarningLine } from '@remixicon/vue'
54
41
  import * as pdfjsLib from 'pdfjs-dist'
55
42
  import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
56
43
  import type { PDFDocumentProxy } from 'pdfjs-dist'
57
- import SimpleBanner from '../SimpleBanner.vue'
44
+ import PreviewUnavailable from './PreviewUnavailable.vue'
58
45
  import { useComponentsConfig } from '../../config'
59
46
  import type { Resource } from '../../types/resources'
47
+ import { getResourceFilesize, getResourceCorsStatus } from '../../functions/resources'
60
48
  import { useTranslation } from '../../composables/useTranslation'
61
- import { getResourceFilesize } from '../../functions/datasets'
62
49
 
63
50
  pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker
64
51
 
@@ -113,6 +100,8 @@ async function renderPage(pageNum: number) {
113
100
 
114
101
  const fileSizeBytes = computed(() => getResourceFilesize(props.resource))
115
102
 
103
+ const corsStatus = computed(() => getResourceCorsStatus(props.resource))
104
+
116
105
  const shouldLoadPdf = computed(() => {
117
106
  const size = fileSizeBytes.value
118
107
  if (!size) {
@@ -126,14 +115,21 @@ const shouldLoadPdf = computed(() => {
126
115
  })
127
116
 
128
117
  const loadPdf = async () => {
118
+ error.value = null
119
+ fileTooLarge.value = false
120
+
129
121
  if (!shouldLoadPdf.value) {
130
122
  fileTooLarge.value = true
131
123
  return
132
124
  }
133
125
 
134
- loading.value = true
135
- error.value = null
126
+ // Check if CORS is allowed
127
+ if (corsStatus.value === 'blocked') {
128
+ error.value = 'cors'
129
+ return
130
+ }
136
131
 
132
+ loading.value = true
137
133
  try {
138
134
  const loadingTask = pdfjsLib.getDocument({
139
135
  url: props.resource.url,
@@ -1,13 +1,8 @@
1
1
  <template>
2
2
  <div>
3
- <SimpleBanner
4
- v-if="hasError"
5
- type="warning"
6
- class="flex items-center space-x-2"
7
- >
8
- <RiErrorWarningLine class="shrink-0 size-6" />
9
- <span>{{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}</span>
10
- </SimpleBanner>
3
+ <PreviewUnavailable v-if="hasError">
4
+ {{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}
5
+ </PreviewUnavailable>
11
6
  <div
12
7
  v-else
13
8
  class="-mx-4"
@@ -53,7 +48,7 @@
53
48
 
54
49
  <script setup lang="ts">
55
50
  import { computed, onMounted, ref, useTemplateRef } from 'vue'
56
- import { RiErrorWarningLine, RiExternalLinkFill } from '@remixicon/vue'
51
+ import { RiExternalLinkFill } from '@remixicon/vue'
57
52
  import { Protocol, PMTiles } from 'pmtiles'
58
53
  import maplibregl from 'maplibre-gl'
59
54
  import DOMPurify from 'dompurify'
@@ -64,7 +59,7 @@ import type { Resource } from '../../types/resources'
64
59
  import type { Dataset, DatasetV2 } from '../../types/datasets'
65
60
  import BrandedButton from '../BrandedButton.vue'
66
61
  import styleVector from '../../../assets/json/vector.json'
67
- import SimpleBanner from '../SimpleBanner.vue'
62
+ import PreviewUnavailable from './PreviewUnavailable.vue'
68
63
  import { useTranslation } from '../../composables/useTranslation'
69
64
  import franceSvg from './france.svg?raw'
70
65
  import { getOwnerName, getOwnerPage } from '../../functions/owned'
@@ -1,13 +1,8 @@
1
1
  <template>
2
2
  <div>
3
- <SimpleBanner
4
- v-if="hasError"
5
- type="warning"
6
- class="flex items-center space-x-2"
7
- >
8
- <RiErrorWarningLine class="shrink-0 size-6" />
9
- <span>{{ t("L'aperçu de ce fichier n'a pas pu être chargé.") }}</span>
10
- </SimpleBanner>
3
+ <PreviewUnavailable v-if="hasError">
4
+ {{ t("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.") }}
5
+ </PreviewUnavailable>
11
6
  <PreviewLoader v-else-if="loading" />
12
7
  <div
13
8
  v-else
@@ -105,7 +100,7 @@
105
100
 
106
101
  <script setup lang="ts">
107
102
  import { computed, onMounted, ref } from 'vue'
108
- import { RiArrowDownLine, RiArrowUpLine, RiErrorWarningLine, RiExternalLinkFill } from '@remixicon/vue'
103
+ import { RiArrowDownLine, RiArrowUpLine, RiExternalLinkFill } from '@remixicon/vue'
109
104
  import Pagination from '../Pagination.vue'
110
105
  import { getData, type SortConfig } from '../../functions/tabularApi'
111
106
  import { useFormatDate } from '../../functions/dates'
@@ -113,7 +108,7 @@ import { trackEvent } from '../../functions/matomo'
113
108
  import type { Resource } from '../../types/resources'
114
109
  import { useComponentsConfig } from '../../config'
115
110
  import BrandedButton from '../BrandedButton.vue'
116
- import SimpleBanner from '../SimpleBanner.vue'
111
+ import PreviewUnavailable from './PreviewUnavailable.vue'
117
112
  import { useTranslation } from '../../composables/useTranslation'
118
113
  import franceSvg from './france.svg?raw'
119
114
  import PreviewLoader from './PreviewLoader.vue'
@@ -147,7 +142,7 @@ async function getTableInfos(page: number, sortConfig?: SortConfig) {
147
142
  try {
148
143
  // Check that this function return wanted data
149
144
  const response = await getData(config, props.resource.id, page, sortConfig)
150
- if ('data' in response && response.data && 0 in response.data) {
145
+ if ('data' in response && response.data && response.data.length > 0) {
151
146
  // Update existing rows
152
147
  rows.value = response.data
153
148
  columns.value = Object.keys(response.data[0]).filter(item => item !== '__id')
@@ -1,7 +1,6 @@
1
1
  <template>
2
2
  <ContentLoader
3
- :width="1124"
4
- :height="300"
3
+ viewBox="0 0 1124 300"
5
4
  :speed="2"
6
5
  primary-color="#f3f3f3"
7
6
  secondary-color="#ecebeb"
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <div class="flex flex-col items-center py-12">
3
+ <img
4
+ :src="microscopeSrc"
5
+ class="h-20 mb-3"
6
+ alt=""
7
+ >
8
+ <p class="fr-text--bold mb-1">
9
+ {{ t("Aucun aperçu disponible") }}
10
+ </p>
11
+ <p class="text-sm text-gray-medium mb-0 text-center max-w-lg">
12
+ <slot />
13
+ </p>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { useTranslation } from '../../composables/useTranslation'
19
+ import microscopeSrc from '../../../assets/illustrations/microscope.svg?url'
20
+
21
+ const { t } = useTranslation()
22
+ </script>
@@ -387,9 +387,8 @@ import { trackEvent } from '../../functions/matomo'
387
387
  import CopyButton from '../CopyButton.vue'
388
388
  import { useComponentsConfig } from '../../config'
389
389
  import { getOwnerName } from '../../functions/owned'
390
- import { getResourceFormatIcon, getResourceTitleId, detectOgcService } from '../../functions/resources'
390
+ import { getResourceFormatIcon, getResourceTitleId, detectOgcService, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
391
391
  import BrandedButton from '../BrandedButton.vue'
392
- import { getResourceExternalUrl, getResourceFilesize } from '../../functions/datasets'
393
392
  import { useTranslation } from '../../composables/useTranslation'
394
393
  import { useHasTabularData } from '../../composables/useHasTabularData'
395
394
  import Metadata from './Metadata.vue'