@datagouv/components-next 0.0.7 → 0.0.9
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.
- package/README.md +34 -14
- package/assets/json/vector.json +2377 -0
- package/assets/main.css +3 -0
- package/assets/swagger-themes/newspaper.css +1669 -0
- package/assets/tailwind.config.js +1 -1
- package/dist/JsonPreview.client-BIz1_EiB.js +92 -0
- package/dist/MapContainer.client-ZDwr4Q_I.js +78276 -0
- package/dist/PdfPreview.client-BTTMM27i.js +112 -0
- package/dist/Pmtiles.client-4kOoUQcR.js +22377 -0
- package/dist/Swagger.client-Q7a5wb51.js +4 -0
- package/dist/XmlPreview.client-BYIIkDqf.js +84 -0
- package/dist/components-next.css +52 -1
- package/dist/components-next.js +42 -41
- package/dist/components.css +1 -1
- package/dist/main-CLUk9Jj7.js +105843 -0
- package/dist/pdf-vue3-BZh6kzke.js +273 -0
- package/dist/pdf.min-f72cfa08-DAetWL3M.js +9501 -0
- package/dist/{text-clamp.esm-DurZFOvT.js → text-clamp.esm-DP59tec5.js} +1 -1
- package/dist/vue3-json-viewer-DIQzFF6K.js +1089 -0
- package/dist/vue3-xml-viewer.common-BmKw6vER.js +5437 -0
- package/package.json +7 -5
- package/src/components/AvatarWithName.vue +6 -2
- package/src/components/BannerAction.vue +1 -1
- package/src/components/BrandedButton.vue +13 -8
- package/src/components/CopyButton.vue +7 -7
- package/src/components/DataserviceCard.vue +54 -23
- package/src/components/DatasetCard.vue +36 -24
- package/src/components/DatasetInformationPanel.vue +19 -18
- package/src/components/DatasetQuality.vue +21 -18
- package/src/components/DatasetQualityInline.vue +1 -1
- package/src/components/DatasetQualityItem.vue +3 -3
- package/src/components/DatasetQualityItemWarning.vue +2 -2
- package/src/components/DatasetQualityScore.vue +2 -2
- package/src/components/DatasetQualityTooltipContent.vue +29 -29
- package/src/components/DescriptionDetails.vue +2 -2
- package/src/components/ExtraAccordion.vue +10 -7
- package/src/components/OrganizationCard.vue +9 -4
- package/src/components/OrganizationNameWithCertificate.vue +25 -11
- package/src/components/Pagination.vue +26 -15
- package/src/components/ReadMore.vue +2 -2
- package/src/components/ResourceAccordion/DataStructure.vue +2 -2
- package/src/components/ResourceAccordion/EditButton.vue +10 -6
- package/src/components/ResourceAccordion/JsonPreview.client.vue +153 -0
- package/src/components/ResourceAccordion/MapContainer.client.vue +137 -0
- package/src/components/ResourceAccordion/Metadata.vue +33 -54
- package/src/components/ResourceAccordion/PdfPreview.client.vue +189 -0
- package/src/components/ResourceAccordion/Pmtiles.client.vue +166 -0
- package/src/components/ResourceAccordion/Preview.vue +39 -37
- package/src/components/ResourceAccordion/ResourceAccordion.vue +141 -63
- package/src/components/ResourceAccordion/ResourceIcon.vue +7 -1
- package/src/components/ResourceAccordion/SchemaBadge.vue +26 -26
- package/src/components/ResourceAccordion/{Swagger.vue → Swagger.client.vue} +1 -1
- package/src/components/ResourceAccordion/XmlPreview.client.vue +143 -0
- package/src/components/ReuseCard.vue +10 -7
- package/src/components/ReuseDetails.vue +3 -3
- package/src/components/SimpleBanner.vue +7 -4
- package/src/components/SmallChart.vue +23 -9
- package/src/components/StatBox.vue +92 -10
- package/src/config.ts +6 -2
- package/src/functions/api.ts +18 -18
- package/src/functions/dates.ts +81 -74
- package/src/functions/helpers.ts +5 -4
- package/src/functions/organizations.ts +5 -5
- package/src/functions/resources.ts +34 -5
- package/src/functions/schemas.ts +4 -3
- package/src/functions/tabularApi.ts +1 -1
- package/src/main.ts +10 -11
- package/src/types/badges.ts +3 -3
- package/src/types/contact_point.ts +5 -5
- package/src/types/dataservices.ts +16 -2
- package/src/types/datasets.ts +20 -2
- package/src/types/frequency.ts +5 -5
- package/src/types/granularity.ts +12 -4
- package/src/types/harvest.ts +2 -2
- package/src/types/licenses.ts +8 -8
- package/src/types/organizations.ts +6 -0
- package/src/types/resources.ts +3 -3
- package/src/types/reuses.ts +3 -1
- package/src/types/site.ts +8 -0
- package/src/types/ui.ts +2 -2
- package/src/types/users.ts +24 -8
- package/src/types/vue3-xml-viewer.d.ts +10 -0
- package/dist/Swagger-DjysB-OI.js +0 -67851
- package/dist/en-DCRve7vN.js +0 -613
- package/dist/fr-DCOnbL-p.js +0 -613
- package/dist/locales/de.js +0 -155
- package/dist/locales/en.js +0 -155
- package/dist/locales/es.js +0 -155
- package/dist/locales/fr.js +0 -155
- package/dist/locales/it.js +0 -155
- package/dist/locales/pt.js +0 -155
- package/dist/locales/sr.js +0 -155
- package/dist/main-CPW2vNLE.js +0 -32008
- package/src/components/DescriptionList/DescriptionDetails.stories.ts +0 -43
- package/src/components/DescriptionList/DescriptionList.stories.ts +0 -47
- package/src/components/DescriptionList/DescriptionTerm.stories.ts +0 -28
- package/src/locales/de.json +0 -154
- package/src/locales/en.json +0 -154
- package/src/locales/es.json +0 -154
- package/src/locales/fr.json +0 -154
- package/src/locales/it.json +0 -154
- package/src/locales/pt.json +0 -154
- package/src/locales/sr.json +0 -154
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="border border-gray-default"
|
|
3
|
+
class="border border-gray-default overflow-auto"
|
|
4
4
|
:class="{ 'fr-pb-4v': open }"
|
|
5
5
|
>
|
|
6
6
|
<header
|
|
7
7
|
:id="resourceHeaderId"
|
|
8
|
-
class="fr-p-4v flex items-center justify-between relative"
|
|
8
|
+
class="fr-p-4v flex flex-wrap gap-4 items-center justify-between relative"
|
|
9
9
|
>
|
|
10
10
|
<div>
|
|
11
11
|
<div class="flex items-center fr-mb-1v">
|
|
@@ -25,22 +25,28 @@
|
|
|
25
25
|
class="size-3.5 mr-1"
|
|
26
26
|
/>
|
|
27
27
|
<span
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
v-if="open"
|
|
29
|
+
class="font-bold text-left"
|
|
30
|
+
><component
|
|
31
|
+
:is="config.textClamp"
|
|
32
|
+
v-if="config && config.textClamp"
|
|
33
|
+
:max-lines="2"
|
|
34
|
+
:text="resource.title || t('Fichier sans nom')"
|
|
35
|
+
/></span>
|
|
36
|
+
<span
|
|
37
|
+
v-else
|
|
31
38
|
><component
|
|
32
39
|
:is="config.textClamp"
|
|
33
40
|
v-if="config && config.textClamp"
|
|
34
41
|
:max-lines="1"
|
|
35
|
-
:text="resource.title || t('
|
|
42
|
+
:text="resource.title || t('Fichier sans nom')"
|
|
36
43
|
/></span>
|
|
37
|
-
|
|
38
44
|
<span class="absolute inset-0 z-1" />
|
|
39
45
|
</button>
|
|
40
46
|
</h4>
|
|
41
47
|
<CopyButton
|
|
42
|
-
:label="$t('
|
|
43
|
-
:copied-label="$t('
|
|
48
|
+
:label="$t('Copier le lien')"
|
|
49
|
+
:copied-label="$t('Lien copié !')"
|
|
44
50
|
:text="resourceExternalUrl"
|
|
45
51
|
class="z-2"
|
|
46
52
|
/>
|
|
@@ -50,7 +56,7 @@
|
|
|
50
56
|
:resource
|
|
51
57
|
class="dash-after"
|
|
52
58
|
/>
|
|
53
|
-
<span class="fr-text--xs fr-mb-0 dash-after">{{ t('
|
|
59
|
+
<span class="fr-text--xs fr-mb-0 dash-after">{{ t('Mis à jour {date}', { date: formatRelativeIfRecentDate(lastUpdate) }) }}</span>
|
|
54
60
|
<span
|
|
55
61
|
v-if="resource.format"
|
|
56
62
|
class="fr-text--xs fr-mb-0 dash-after"
|
|
@@ -61,17 +67,17 @@
|
|
|
61
67
|
</span>
|
|
62
68
|
<span
|
|
63
69
|
class="inline-flex items-center fr-text--xs fr-mb-0"
|
|
64
|
-
:aria-label="t('{n}
|
|
70
|
+
:aria-label="t('{n} téléchargements', resource.metrics.views)"
|
|
65
71
|
>
|
|
66
72
|
<span class="fr-icon-download-line fr-icon--xs fr-mr-1v" />
|
|
67
|
-
<span>{{ summarize(resource.metrics.views) }} <span class="hidden show-on-small">{{ t("
|
|
73
|
+
<span>{{ summarize(resource.metrics.views) }} <span class="hidden show-on-small">{{ t("téléchargements") }}</span></span>
|
|
68
74
|
</span>
|
|
69
75
|
</div>
|
|
70
76
|
<p
|
|
71
77
|
v-if="communityResource"
|
|
72
78
|
class="fr-mb-0 fr-mt-1v fr-text--xs text-gray-medium"
|
|
73
79
|
>
|
|
74
|
-
{{ t('
|
|
80
|
+
{{ t('Par') }}
|
|
75
81
|
<a
|
|
76
82
|
v-if="communityResource.organization"
|
|
77
83
|
class="fr-link fr-text--xs"
|
|
@@ -84,26 +90,21 @@
|
|
|
84
90
|
</template>
|
|
85
91
|
</p>
|
|
86
92
|
</div>
|
|
87
|
-
<div class="flex items-center
|
|
88
|
-
<p
|
|
89
|
-
v-if="unavailable"
|
|
90
|
-
class="text-default-warning fr-m-0 fr-mr-2v"
|
|
91
|
-
>
|
|
92
|
-
{{ t('Unavailable') }}
|
|
93
|
-
</p>
|
|
93
|
+
<div class="flex items-center buttons">
|
|
94
94
|
<p
|
|
95
95
|
v-if="resource.format === 'url'"
|
|
96
96
|
class="fr-col-auto fr-ml-3v fr-m-0 z-2"
|
|
97
97
|
>
|
|
98
98
|
<BrandedButton
|
|
99
99
|
:href="resource.latest"
|
|
100
|
-
:title="t('
|
|
100
|
+
:title="t('Lien du fichier - ouvre une nouvelle fenêtre')"
|
|
101
101
|
:aria-describedby="resourceTitleId"
|
|
102
102
|
rel="ugc nofollow noopener"
|
|
103
103
|
new-tab
|
|
104
104
|
size="xs"
|
|
105
|
+
external
|
|
105
106
|
>
|
|
106
|
-
{{ $t('
|
|
107
|
+
{{ $t('Visiter') }}
|
|
107
108
|
</BrandedButton>
|
|
108
109
|
</p>
|
|
109
110
|
<p
|
|
@@ -118,7 +119,7 @@
|
|
|
118
119
|
size="xs"
|
|
119
120
|
:icon="RiFileCopyLine"
|
|
120
121
|
>
|
|
121
|
-
{{ t('
|
|
122
|
+
{{ t('Copier le lien') }}
|
|
122
123
|
</BrandedButton>
|
|
123
124
|
</p>
|
|
124
125
|
<p
|
|
@@ -128,14 +129,15 @@
|
|
|
128
129
|
<BrandedButton
|
|
129
130
|
:href="resource.latest"
|
|
130
131
|
rel="ugc nofollow noopener"
|
|
131
|
-
:title="
|
|
132
|
+
:title="downloadButtonTitle"
|
|
132
133
|
download
|
|
133
134
|
class="relative text-transform-uppercase matomo_download z-2"
|
|
134
|
-
:icon="RiDownloadLine"
|
|
135
|
+
:icon="unavailable ? RiFileWarningLine : RiDownloadLine"
|
|
135
136
|
size="xs"
|
|
136
137
|
:aria-describedby="resourceTitleId"
|
|
138
|
+
external
|
|
137
139
|
>
|
|
138
|
-
<span class="sr-only">{{ t('
|
|
140
|
+
<span class="sr-only">{{ t('Télécharger la liste au format ') }}</span>{{ format }}
|
|
139
141
|
</BrandedButton>
|
|
140
142
|
</p>
|
|
141
143
|
<p
|
|
@@ -146,6 +148,7 @@
|
|
|
146
148
|
:dataset-id="dataset.id"
|
|
147
149
|
:resource-id="resource.id"
|
|
148
150
|
:is-community-resource="isCommunityResource"
|
|
151
|
+
size="xs"
|
|
149
152
|
/>
|
|
150
153
|
</p>
|
|
151
154
|
<div
|
|
@@ -177,13 +180,42 @@
|
|
|
177
180
|
<TabPanel
|
|
178
181
|
v-for="tab in tabsOptions"
|
|
179
182
|
:key="tab.key"
|
|
183
|
+
class="px-4"
|
|
180
184
|
>
|
|
185
|
+
<div v-if="tab.key === 'map'">
|
|
186
|
+
<Pmtiles
|
|
187
|
+
v-if="hasPmtiles"
|
|
188
|
+
:resource="resource"
|
|
189
|
+
/>
|
|
190
|
+
<MapContainer
|
|
191
|
+
v-if="ogcWms"
|
|
192
|
+
:resource="resource"
|
|
193
|
+
/>
|
|
194
|
+
</div>
|
|
181
195
|
<div v-if="tab.key === 'data'">
|
|
182
|
-
|
|
196
|
+
<!-- Show JSON viewer for JSON files -->
|
|
197
|
+
<JsonPreview
|
|
198
|
+
v-if="resource.format && resource.format.toLowerCase() === 'json'"
|
|
199
|
+
:resource="resource"
|
|
200
|
+
/>
|
|
201
|
+
<!-- Show PDF viewer for PDF files -->
|
|
202
|
+
<PdfPreview
|
|
203
|
+
v-else-if="resource.format && resource.format.toLowerCase() === 'pdf'"
|
|
204
|
+
:resource="resource"
|
|
205
|
+
/>
|
|
206
|
+
<!-- Show XML viewer for XML files -->
|
|
207
|
+
<XmlPreview
|
|
208
|
+
v-else-if="resource.format && resource.format.toLowerCase() === 'xml'"
|
|
209
|
+
:resource="resource"
|
|
210
|
+
/>
|
|
211
|
+
<!-- Show regular preview for other file types -->
|
|
212
|
+
<Preview
|
|
213
|
+
v-else
|
|
214
|
+
:resource="resource"
|
|
215
|
+
/>
|
|
183
216
|
</div>
|
|
184
217
|
<div
|
|
185
218
|
v-if="tab.key === 'description'"
|
|
186
|
-
class="fr-pl-4v fr-pr-4v"
|
|
187
219
|
>
|
|
188
220
|
<div
|
|
189
221
|
class="fr-mt-0 markdown fr-text--sm text-mention-grey"
|
|
@@ -192,37 +224,34 @@
|
|
|
192
224
|
</div>
|
|
193
225
|
<div
|
|
194
226
|
v-if="tab.key === 'data-structure'"
|
|
195
|
-
class="fr-pl-4v fr-pr-4v"
|
|
196
227
|
>
|
|
197
228
|
<DataStructure
|
|
198
|
-
v-if="
|
|
229
|
+
v-if="hasTabularData"
|
|
199
230
|
:resource="resource"
|
|
200
231
|
/>
|
|
201
232
|
</div>
|
|
202
233
|
<div
|
|
203
234
|
v-if="tab.key === 'metadata'"
|
|
204
|
-
class="fr-pl-4v fr-pr-4v"
|
|
205
235
|
>
|
|
206
236
|
<Metadata :resource />
|
|
207
237
|
</div>
|
|
208
238
|
<div
|
|
209
239
|
v-if="tab.key === 'downloads'"
|
|
210
|
-
class="fr-pl-4v fr-pr-4v"
|
|
211
240
|
>
|
|
212
241
|
<dl class="fr-pl-0">
|
|
213
242
|
<dt
|
|
214
243
|
v-if="resource.format === 'url'"
|
|
215
244
|
class="font-bold fr-text--sm fr-mb-0"
|
|
216
245
|
>
|
|
217
|
-
{{ $t(
|
|
246
|
+
{{ $t("URL d'origine") }}
|
|
218
247
|
</dt>
|
|
219
248
|
<dt
|
|
220
249
|
v-else
|
|
221
250
|
class="font-bold fr-text--sm fr-mb-0"
|
|
222
251
|
>
|
|
223
|
-
{{ $t('
|
|
252
|
+
{{ $t('Format original') }}
|
|
224
253
|
</dt>
|
|
225
|
-
<dd class="text-sm
|
|
254
|
+
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
|
|
226
255
|
<span v-if="resource.format === 'url'">
|
|
227
256
|
<a
|
|
228
257
|
:href="resource.latest"
|
|
@@ -254,31 +283,35 @@
|
|
|
254
283
|
</a>
|
|
255
284
|
</span>
|
|
256
285
|
<CopyButton
|
|
257
|
-
:label="$t('
|
|
258
|
-
:copied-label="$t('
|
|
286
|
+
:label="$t('Copier le lien')"
|
|
287
|
+
:copied-label="$t('Lien copié !')"
|
|
259
288
|
:text="resource.latest"
|
|
260
289
|
class="relative"
|
|
261
290
|
/>
|
|
262
291
|
</dd>
|
|
263
|
-
<template v-if="
|
|
292
|
+
<template v-if="generatedFormats.length">
|
|
264
293
|
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
265
|
-
{{ $t('
|
|
294
|
+
{{ $t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
|
|
266
295
|
</dt>
|
|
267
|
-
<dd
|
|
296
|
+
<dd
|
|
297
|
+
v-for="generatedFormat in generatedFormats"
|
|
298
|
+
:key="generatedFormat.format"
|
|
299
|
+
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
300
|
+
>
|
|
268
301
|
<span>
|
|
269
302
|
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
270
303
|
<a
|
|
271
|
-
:href="
|
|
304
|
+
:href="generatedFormat.url"
|
|
272
305
|
class="fr-link"
|
|
273
306
|
rel="ugc nofollow noopener"
|
|
274
307
|
>
|
|
275
|
-
<span>{{ $t('Format {format}', { format:
|
|
308
|
+
<span>{{ $t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
|
|
276
309
|
</a>
|
|
277
310
|
</span>
|
|
278
311
|
<CopyButton
|
|
279
|
-
:label="$t('
|
|
280
|
-
:copied-label="$t('
|
|
281
|
-
:text="
|
|
312
|
+
:label="$t('Copier le lien')"
|
|
313
|
+
:copied-label="$t('Lien copié !')"
|
|
314
|
+
:text="generatedFormat.url"
|
|
282
315
|
class="relative"
|
|
283
316
|
/>
|
|
284
317
|
</dd>
|
|
@@ -287,11 +320,10 @@
|
|
|
287
320
|
</div>
|
|
288
321
|
<div
|
|
289
322
|
v-if="tab.key === 'swagger'"
|
|
290
|
-
class="fr-pl-4v fr-pr-4v"
|
|
291
323
|
>
|
|
292
|
-
<div>{{ t(
|
|
324
|
+
<div>{{ t("Swagger généré automatiquement par {platform}. Ce swagger vous permet d'interroger les données par API en les filtrant par valeur de colonne.", { platform: config.name }) }}</div>
|
|
293
325
|
<Swagger
|
|
294
|
-
v-if="
|
|
326
|
+
v-if="hasTabularData"
|
|
295
327
|
:url="`${config.tabularApiUrl}/api/resources/${props.resource.id}/swagger/`"
|
|
296
328
|
/>
|
|
297
329
|
</div>
|
|
@@ -305,11 +337,11 @@
|
|
|
305
337
|
<script setup lang="ts">
|
|
306
338
|
import { ref, computed, defineAsyncComponent } from 'vue'
|
|
307
339
|
import { useI18n } from 'vue-i18n'
|
|
308
|
-
import { RiDownloadLine, RiFileCopyLine } from '@remixicon/vue'
|
|
340
|
+
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine } from '@remixicon/vue'
|
|
309
341
|
import OrganizationNameWithCertificate from '../OrganizationNameWithCertificate.vue'
|
|
310
342
|
import { filesize, summarize } from '../../functions/helpers'
|
|
311
343
|
import { markdown } from '../../functions/markdown'
|
|
312
|
-
import {
|
|
344
|
+
import { useFormatDate } from '../../functions/dates'
|
|
313
345
|
import type { CommunityResource, Resource } from '../../types/resources'
|
|
314
346
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
315
347
|
import TabGroup from '../Tabs/TabGroup.vue'
|
|
@@ -321,7 +353,7 @@ import { trackEvent } from '../../functions/matomo'
|
|
|
321
353
|
import CopyButton from '../CopyButton.vue'
|
|
322
354
|
import { useComponentsConfig } from '../../config'
|
|
323
355
|
import { getOwnerName } from '../../functions/owned'
|
|
324
|
-
import { getResourceFormatIcon, getResourceTitleId } from '../../functions/resources'
|
|
356
|
+
import { getResourceFormatIcon, getResourceTitleId, detectOgcService } from '../../functions/resources'
|
|
325
357
|
import BrandedButton from '../BrandedButton.vue'
|
|
326
358
|
import { getResourceExternalUrl } from '../../functions/datasets'
|
|
327
359
|
import Metadata from './Metadata.vue'
|
|
@@ -331,7 +363,7 @@ import EditButton from './EditButton.vue'
|
|
|
331
363
|
import DataStructure from './DataStructure.vue'
|
|
332
364
|
import Preview from './Preview.vue'
|
|
333
365
|
|
|
334
|
-
const
|
|
366
|
+
const GENERATED_FORMATS = ['parquet', 'pmtiles', 'geojson']
|
|
335
367
|
|
|
336
368
|
const props = withDefaults(defineProps<{
|
|
337
369
|
dataset: Dataset | DatasetV2
|
|
@@ -347,20 +379,59 @@ const props = withDefaults(defineProps<{
|
|
|
347
379
|
|
|
348
380
|
const config = useComponentsConfig()
|
|
349
381
|
|
|
350
|
-
const Swagger = defineAsyncComponent(() => import('./Swagger.vue'))
|
|
382
|
+
const Swagger = defineAsyncComponent(() => import('./Swagger.client.vue'))
|
|
383
|
+
const MapContainer = defineAsyncComponent(() => import('./MapContainer.client.vue'))
|
|
384
|
+
const Pmtiles = defineAsyncComponent(() => import('./Pmtiles.client.vue'))
|
|
385
|
+
const JsonPreview = defineAsyncComponent(() => import('./JsonPreview.client.vue'))
|
|
386
|
+
const PdfPreview = defineAsyncComponent(() => import('./PdfPreview.client.vue'))
|
|
387
|
+
const XmlPreview = defineAsyncComponent(() => import('./XmlPreview.client.vue'))
|
|
351
388
|
|
|
352
389
|
const { t } = useI18n()
|
|
390
|
+
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
353
391
|
|
|
354
392
|
const hasPreview = computed(() => {
|
|
393
|
+
// For JSON, PDF, and XML files, show preview.
|
|
394
|
+
// We cannot check for CORS issues here because we cannot use an async component here.
|
|
395
|
+
// 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.
|
|
396
|
+
const format = props.resource.format?.toLowerCase()
|
|
397
|
+
return format === 'json' || format === 'pdf' || format === 'xml'
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
const hasTabularData = computed(() => {
|
|
401
|
+
// Determines if we should show the "Données" tab for tabular files AND the "Structure des données" tab (for tabular data structure)
|
|
355
402
|
return config.tabularApiUrl
|
|
356
|
-
&& props.resource.extras['analysis:parsing:
|
|
403
|
+
&& props.resource.extras['analysis:parsing:parsing_table']
|
|
357
404
|
&& !props.resource.extras['analysis:parsing:error']
|
|
358
405
|
&& (config.tabularAllowRemote || props.resource.filetype === 'file')
|
|
359
406
|
})
|
|
360
407
|
|
|
361
|
-
const
|
|
408
|
+
const hasPmtiles = computed(() => {
|
|
409
|
+
return props.resource.extras['analysis:parsing:pmtiles_url']
|
|
410
|
+
})
|
|
362
411
|
|
|
363
|
-
const
|
|
412
|
+
const format = computed(() => getResourceFormatIcon(props.resource.format) ? props.resource.format : t('Fichier'))
|
|
413
|
+
|
|
414
|
+
const ogcService = computed(() => detectOgcService(props.resource))
|
|
415
|
+
|
|
416
|
+
const ogcWms = computed(() => ogcService.value === 'wms')
|
|
417
|
+
|
|
418
|
+
const generatedFormats = computed(() => {
|
|
419
|
+
const formats = GENERATED_FORMATS
|
|
420
|
+
.filter(format => `analysis:parsing:${format}_url` in props.resource.extras)
|
|
421
|
+
.map(format => ({
|
|
422
|
+
url: props.resource.extras[`analysis:parsing:${format}_url`] as string,
|
|
423
|
+
size: props.resource.extras[`analysis:parsing:${format}_size`] as number | undefined,
|
|
424
|
+
format: format,
|
|
425
|
+
}))
|
|
426
|
+
if ('analysis:parsing:parsing_table' in props.resource.extras) {
|
|
427
|
+
formats.push({
|
|
428
|
+
url: `${config.tabularApiUrl}/api/resources/${props.resource.id}/data/json/`,
|
|
429
|
+
size: undefined,
|
|
430
|
+
format: 'json',
|
|
431
|
+
})
|
|
432
|
+
}
|
|
433
|
+
return formats
|
|
434
|
+
})
|
|
364
435
|
|
|
365
436
|
const open = ref(props.expandedOnMount)
|
|
366
437
|
const toggle = () => {
|
|
@@ -377,22 +448,26 @@ const toggle = () => {
|
|
|
377
448
|
const tabsOptions = computed(() => {
|
|
378
449
|
const options = []
|
|
379
450
|
|
|
380
|
-
if (
|
|
381
|
-
options.push({ key: '
|
|
451
|
+
if (hasPmtiles.value || ogcWms.value) {
|
|
452
|
+
options.push({ key: 'map', label: t('Carte') })
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (hasTabularData.value || hasPreview.value) {
|
|
456
|
+
options.push({ key: 'data', label: t('Aperçu') })
|
|
382
457
|
}
|
|
383
458
|
|
|
384
459
|
if (props.resource.description) {
|
|
385
460
|
options.push({ key: 'description', label: t('Description') })
|
|
386
461
|
}
|
|
387
462
|
|
|
388
|
-
if (
|
|
389
|
-
options.push({ key: 'data-structure', label: t('
|
|
463
|
+
if (hasTabularData.value) {
|
|
464
|
+
options.push({ key: 'data-structure', label: t('Structure des données') })
|
|
390
465
|
}
|
|
391
466
|
|
|
392
|
-
options.push({ key: 'metadata', label: t('
|
|
393
|
-
options.push({ key: 'downloads', label: t('
|
|
467
|
+
options.push({ key: 'metadata', label: t('Métadonnées') })
|
|
468
|
+
options.push({ key: 'downloads', label: t('Téléchargements') })
|
|
394
469
|
|
|
395
|
-
if (
|
|
470
|
+
if (hasTabularData.value) {
|
|
396
471
|
options.push({ key: 'swagger', label: t('Swagger') })
|
|
397
472
|
}
|
|
398
473
|
|
|
@@ -417,8 +492,11 @@ const communityResource = computed<CommunityResource | null>(() => {
|
|
|
417
492
|
const owner = computed(() => communityResource.value ? getOwnerName(communityResource.value) : null)
|
|
418
493
|
|
|
419
494
|
const lastUpdate = props.resource.last_modified
|
|
495
|
+
const conversionsLastUpdate = computed(() => formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at']))
|
|
420
496
|
const availabilityChecked = props.resource.extras && 'check:available' in props.resource.extras
|
|
497
|
+
|
|
421
498
|
const unavailable = availabilityChecked && props.resource.extras['check:available'] === false
|
|
499
|
+
const downloadButtonTitle = unavailable ? t(`Le robot de {certifier} n'a pas pu accéder à ce fichier - Télécharger le fichier en {format}`, { certifier: config.name, format: format.value }) : t(`Télécharger le fichier en {format}`, { format: format.value })
|
|
422
500
|
|
|
423
501
|
const resourceExternalUrl = computed(() => getResourceExternalUrl(props.dataset, props.resource))
|
|
424
502
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
:is="(resource.
|
|
3
|
+
:is="(resource.format ? getResourceFormatIcon(resource.format) : null) || File"
|
|
4
4
|
class="text-gray-800 shrink-0"
|
|
5
5
|
/>
|
|
6
6
|
</template>
|
|
@@ -11,6 +11,12 @@ import File from '../Icons/File.vue'
|
|
|
11
11
|
import { getResourceFormatIcon } from '../../functions/resources'
|
|
12
12
|
|
|
13
13
|
defineProps<{
|
|
14
|
+
// We would like to use Resource | ResourceForm but ResourceForm is not in
|
|
15
|
+
// datagouv/components yet. We don't use `filetype` but we need otherwise
|
|
16
|
+
// TS don't like passing some object without `format` because it would have
|
|
17
|
+
// nothing in common with `{}`. We could do `{ format: … } | object` but it's
|
|
18
|
+
// really generic and I prefer to have something like `filetype` which is specific
|
|
19
|
+
// to resources' objects.
|
|
14
20
|
resource: { format?: string | null, filetype: ResourceFileType | null }
|
|
15
21
|
}>()
|
|
16
22
|
</script>
|
|
@@ -1,94 +1,94 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<span
|
|
3
3
|
v-if="title"
|
|
4
|
-
class="inline-flex
|
|
4
|
+
class="inline-flex mb-0 items-baseline text-xs"
|
|
5
5
|
>
|
|
6
6
|
<Toggletip
|
|
7
7
|
position="right"
|
|
8
8
|
no-margin
|
|
9
|
-
class="relative z-2"
|
|
9
|
+
class="relative z-2 -ml-3 top-1 -my-3"
|
|
10
10
|
>
|
|
11
11
|
<template #toggletip="{ close }">
|
|
12
12
|
<div class="flex justify-between border-bottom">
|
|
13
|
-
<h5 class="fr-text--sm fr-my-0 fr-p-2v">{{ $t("
|
|
13
|
+
<h5 class="fr-text--sm fr-my-0 fr-p-2v">{{ $t("Schéma de données") }}</h5>
|
|
14
14
|
<button
|
|
15
15
|
type="button"
|
|
16
|
-
:title="t('
|
|
16
|
+
:title="t('Fermer')"
|
|
17
17
|
class="border-left close-button flex items-center justify-center"
|
|
18
18
|
@click="close"
|
|
19
19
|
>×</button>
|
|
20
20
|
</div>
|
|
21
|
-
<div class="
|
|
21
|
+
<div class="p-3">
|
|
22
22
|
<div v-if="validataStatus === 'ok'">
|
|
23
|
-
{{ t("
|
|
23
|
+
{{ t("Ce fichier est valide pour le schéma :") }} <component
|
|
24
24
|
:is="documentationUrl ? 'a' : 'span'"
|
|
25
25
|
:href="documentationUrl"
|
|
26
26
|
class="fr-link fr-text--sm"
|
|
27
27
|
>{{ title }}</component>.
|
|
28
28
|
</div>
|
|
29
29
|
<div v-if="validataStatus === 'warnings'">
|
|
30
|
-
{{ t("
|
|
30
|
+
{{ t("Ce fichier est valide pour le schéma :") }} <component
|
|
31
31
|
:is="documentationUrl ? 'a' : 'span'"
|
|
32
32
|
:href="documentationUrl"
|
|
33
33
|
class="fr-link fr-text--sm"
|
|
34
|
-
>{{ title }}</component>. {{ t("
|
|
34
|
+
>{{ title }}</component>. {{ t("Mais sa conformité peut être améliorée.") }}
|
|
35
35
|
</div>
|
|
36
36
|
<div v-if="validataStatus === 'ko'">
|
|
37
|
-
{{ t("
|
|
37
|
+
{{ t("Ce fichier indique suivre le schéma :") }} <component
|
|
38
38
|
:is="documentationUrl ? 'a' : 'span'"
|
|
39
39
|
:href="documentationUrl"
|
|
40
40
|
class="fr-link fr-text--sm"
|
|
41
|
-
>{{ title }}</component>. {{ t("
|
|
41
|
+
>{{ title }}</component>. {{ t("Mais n'est pas conforme.") }}
|
|
42
42
|
</div>
|
|
43
43
|
|
|
44
44
|
<div
|
|
45
45
|
v-if="validataWarnings.length"
|
|
46
|
-
class="text-default-warning flex items-center
|
|
46
|
+
class="text-default-warning flex items-center mt-4"
|
|
47
47
|
>
|
|
48
|
-
<span class="fr-icon-alert-line fr-icon--sm
|
|
49
|
-
<span>{{ validataWarnings.length }} {{ t('
|
|
48
|
+
<span class="fr-icon-alert-line fr-icon--sm mr-1" />
|
|
49
|
+
<span>{{ validataWarnings.length }} {{ t('recommandations') }}</span>
|
|
50
50
|
</div>
|
|
51
51
|
<div
|
|
52
52
|
v-if="validataStructureErrors.length"
|
|
53
|
-
class="text-default-warning flex items-center
|
|
53
|
+
class="text-default-warning flex items-center mt-4"
|
|
54
54
|
>
|
|
55
|
-
<span class="fr-icon-alert-line fr-icon--sm
|
|
56
|
-
<span>{{ validataStructureErrors.length }} {{ t('
|
|
55
|
+
<span class="fr-icon-alert-line fr-icon--sm mr-1" />
|
|
56
|
+
<span>{{ validataStructureErrors.length }} {{ t('erreurs de structures') }}</span>
|
|
57
57
|
</div>
|
|
58
58
|
<div
|
|
59
59
|
v-if="validataBodyErrors.length"
|
|
60
|
-
class="text-default-warning flex items-center
|
|
60
|
+
class="text-default-warning flex items-center mt-4"
|
|
61
61
|
>
|
|
62
|
-
<span class="fr-icon-alert-line fr-icon--sm
|
|
63
|
-
<span>{{ validataBodyErrors.length }} {{ t('
|
|
62
|
+
<span class="fr-icon-alert-line fr-icon--sm mr-1" />
|
|
63
|
+
<span>{{ validataBodyErrors.length }} {{ t('erreurs de contenus') }}</span>
|
|
64
64
|
</div>
|
|
65
65
|
|
|
66
66
|
<div
|
|
67
67
|
v-if="validationUrl"
|
|
68
|
-
class="w-
|
|
68
|
+
class="w-full text-right mt-5"
|
|
69
69
|
target="_blank"
|
|
70
70
|
>
|
|
71
|
-
<a :href="validationUrl">{{ t('
|
|
71
|
+
<a :href="validationUrl">{{ t('Voir le rapport de validation') }}</a>
|
|
72
72
|
</div>
|
|
73
73
|
</div>
|
|
74
74
|
</template>
|
|
75
75
|
</Toggletip>
|
|
76
|
-
<span class="
|
|
76
|
+
<span class="mr-1 text-gray-medium">{{ t("Schéma:") }}</span>
|
|
77
77
|
<span class="flex items-center bg-danger-lightest rounded-sm">
|
|
78
78
|
<span class="fr-tag fr-tag--sm">{{ title }}</span>
|
|
79
79
|
<span
|
|
80
80
|
v-if="validataStatus === 'warnings'"
|
|
81
81
|
class="flex items-center padding-sm"
|
|
82
82
|
>
|
|
83
|
-
<span class="fr-icon-alert-line fr-icon--sm
|
|
84
|
-
<span>{{ t("
|
|
83
|
+
<span class="fr-icon-alert-line fr-icon--sm mr-1" />
|
|
84
|
+
<span>{{ t("Invalide") }}</span>
|
|
85
85
|
</span>
|
|
86
86
|
<span
|
|
87
87
|
v-if="validataStatus === 'ko'"
|
|
88
88
|
class="flex items-center text-warning-dark padding-sm"
|
|
89
89
|
>
|
|
90
|
-
<span class="fr-icon-error-line fr-icon--sm
|
|
91
|
-
<span>{{ t("
|
|
90
|
+
<span class="fr-icon-error-line fr-icon--sm mr-1" />
|
|
91
|
+
<span>{{ t("Invalide") }}</span>
|
|
92
92
|
</span>
|
|
93
93
|
</span>
|
|
94
94
|
</span>
|