@datagouv/components-next 1.0.2-dev.17 → 1.0.2-dev.171
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 +7 -6
- package/assets/main.css +4 -0
- package/dist/{Control-DuZJdKV_.js → Control-B9WQxlpJ.js} +1 -1
- package/dist/{Datafair.client-Ds3VQrRi.js → Datafair.client-B-OG5WtK.js} +4 -4
- package/dist/{Event--kp8kMdJ.js → Event-iXDrp-fy.js} +31 -31
- package/dist/{Image-34hvypZI.js → Image-mNMBOofs.js} +9 -9
- package/dist/ImagePreview.client-D0c-ifUi.js +36 -0
- package/dist/JsonPreview.client-Dwh9sW9M.js +40 -0
- package/dist/{Map-BjUnLyj8.js → Map-BfqKMw0S.js} +1739 -1599
- package/dist/{MapContainer.client-B2BijMx5.js → MapContainer.client-C2AZ7sOB.js} +38 -39
- package/dist/{OSM-s40W6sQ2.js → OSM-CcrUhItr.js} +15 -23
- package/dist/{PdfPreview.client-DJBMzrlC.js → PdfPreview.client-8NzNfW8b.js} +823 -855
- package/dist/Pmtiles.client-BFH4rTB7.js +26324 -0
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-BOgE441d.js +58 -0
- package/dist/{ScaleLine-KW-nXqp3.js → ScaleLine-VGQ7nkMS.js} +2 -2
- package/dist/{Tile-DbNFNPfU.js → Tile-CSpn0Ca8.js} +160 -163
- package/dist/{TileImage-BsXBxMtq.js → TileImage-CpbaEFwd.js} +143 -131
- package/dist/{View-BR92hTWP.js → View-BYBpt-AU.js} +483 -422
- package/dist/XmlPreview.client-DMOUO508.js +34 -0
- package/dist/{common-PJfpC179.js → common-BoeTUnDZ.js} +52 -52
- package/dist/components-next.css +1 -52
- package/dist/components-next.js +183 -146
- package/dist/components.css +2 -2
- package/dist/{index-BFQX7Ccz.js → index-C9obT9DJ.js} +21834 -15810
- package/dist/{leaflet-src-7m1mB8LI.js → leaflet-src-B4AZU0vr.js} +185 -187
- package/dist/{main-vqhkVhVS.js → main-DNoYWfit.js} +40723 -73240
- package/dist/{proj-DsetBcW7.js → proj-DxGbobp7.js} +662 -626
- package/dist/{text-clamp.esm-B5kW_XMt.js → text-clamp.esm-DVseBqZZ.js} +4 -4
- package/dist/{tilecoord-Db24Px13.js → tilecoord-DvX7WWiA.js} +273 -264
- package/dist/{vue3-json-viewer-BXwup7nO.js → vue3-json-viewer-CJLQFzXZ.js} +10 -16
- package/dist/{vue3-xml-viewer.common-BcNJo35o.js → vue3-xml-viewer.common-Cp7Cu5ME.js} +16 -16
- package/package.json +47 -38
- package/src/chart.ts +5 -0
- package/src/components/ActivityList/ActivityList.vue +3 -2
- package/src/components/Chart/ChartViewer.vue +320 -0
- package/src/components/Chart/ChartViewerWrapper.vue +182 -0
- package/src/components/DataserviceCard.vue +9 -0
- package/src/components/DataserviceQuality.vue +82 -0
- package/src/components/DataserviceQualityInline.vue +31 -0
- package/src/components/DataserviceQualityTooltipContent.vue +79 -0
- package/src/components/DatasetCard.vue +9 -4
- package/src/components/DatasetQuality.vue +11 -11
- package/src/components/DatasetQualityInline.vue +2 -2
- package/src/components/DatasetQualityTooltipContent.vue +1 -1
- package/src/components/Form/Listbox.vue +101 -0
- package/src/components/InfiniteLoader.vue +53 -0
- package/src/components/ObjectCardHeader.vue +11 -4
- package/src/components/OpenApiViewer/ContentTypeSelect.vue +48 -0
- package/src/components/OpenApiViewer/EndpointRequest.vue +164 -0
- package/src/components/OpenApiViewer/EndpointResponses.vue +149 -0
- package/src/components/OpenApiViewer/OpenApiViewer.vue +308 -0
- package/src/components/OpenApiViewer/SchemaPanel.vue +53 -0
- package/src/components/OpenApiViewer/SchemaTree.vue +77 -0
- package/src/components/OpenApiViewer/openapi.ts +150 -0
- package/src/components/OrganizationNameWithCertificate.vue +3 -2
- package/src/components/Pagination.vue +8 -5
- package/src/components/RadioInput.vue +7 -2
- package/src/components/ResourceAccordion/DataStructure.vue +11 -33
- package/src/components/ResourceAccordion/Downloads.vue +160 -0
- package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
- package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -104
- package/src/components/ResourceAccordion/MapContainer.client.vue +1 -3
- package/src/components/ResourceAccordion/Metadata.vue +1 -2
- package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -87
- package/src/components/ResourceAccordion/Pmtiles.client.vue +3 -1
- package/src/components/ResourceAccordion/Preview.vue +11 -11
- package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +19 -113
- package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -98
- package/src/components/ResourceExplorer/ResourceExplorer.vue +22 -19
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +64 -148
- package/src/components/ResourceExplorer/ResourceSelector.vue +113 -0
- package/src/components/ReuseCard.vue +14 -6
- package/src/components/ReuseDetails.vue +2 -2
- package/src/components/ReuseHorizontalCard.vue +2 -2
- package/src/components/Search/GlobalSearch.vue +219 -117
- package/src/components/Search/SearchInput.vue +5 -4
- package/src/components/TabularExplorer/TabularCell.vue +52 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +1226 -0
- package/src/components/TabularExplorer/TabularFilterContent.vue +370 -0
- package/src/components/TabularExplorer/TabularFilterPopover.vue +107 -0
- package/src/components/TabularExplorer/types.ts +86 -0
- package/src/composables/useHasTabularData.ts +15 -1
- package/src/composables/useMetrics.ts +1 -1
- package/src/composables/useResourceCapabilities.ts +28 -15
- package/src/composables/useSearchFilter.ts +120 -0
- package/src/composables/useStableQueryParams.ts +38 -6
- package/src/composables/useTabularProfile.ts +70 -0
- package/src/config.ts +21 -3
- package/src/functions/activities.ts +3 -3
- package/src/functions/api.ts +20 -42
- package/src/functions/api.types.ts +1 -0
- package/src/functions/charts.ts +99 -0
- package/src/functions/datasets.ts +0 -17
- package/src/functions/dates.ts +3 -2
- package/src/functions/metrics.ts +6 -4
- package/src/functions/resources.ts +117 -1
- package/src/functions/tabular.ts +214 -0
- package/src/functions/tabularApi.ts +96 -11
- package/src/main.ts +109 -14
- package/src/types/dataservices.ts +17 -0
- package/src/types/organizations.ts +10 -0
- package/src/types/pages.ts +0 -5
- package/src/types/posts.ts +2 -2
- package/src/types/reports.ts +5 -1
- package/src/types/resources.ts +0 -1
- package/src/types/reuses.ts +12 -1
- package/src/types/search.ts +63 -1
- package/src/types/site.ts +5 -3
- package/src/types/ui.ts +2 -0
- package/src/types/users.ts +2 -1
- package/src/types/visualizations.ts +93 -0
- package/assets/swagger-themes/newspaper.css +0 -1670
- package/dist/JsonPreview.client-CYxmz0yV.js +0 -72
- package/dist/Pmtiles.client-C_hvRDuy.js +0 -25185
- package/dist/Swagger.client-B4y0hXME.js +0 -4
- package/dist/XmlPreview.client-LETEfNBH.js +0 -64
- package/src/components/ResourceAccordion/Swagger.client.vue +0 -48
- package/src/functions/pagination.ts +0 -9
- /package/src/components/{DatasetQualityItem.vue → QualityItem.vue} +0 -0
- /package/src/components/{DatasetQualityItemWarning.vue → QualityItemWarning.vue} +0 -0
- /package/src/components/{DatasetQualityScore.vue → QualityScore.vue} +0 -0
|
@@ -2,24 +2,31 @@
|
|
|
2
2
|
<div class="border border-gray-default">
|
|
3
3
|
<header class="p-4 flex flex-wrap md:flex-nowrap gap-4 items-center justify-between">
|
|
4
4
|
<div>
|
|
5
|
-
<div class="flex items-center mb-1">
|
|
5
|
+
<div class="flex items-center gap-1 mb-1">
|
|
6
6
|
<h3 class="m-0 flex items-baseline text-base font-bold leading-tight">
|
|
7
7
|
<ResourceIcon
|
|
8
8
|
:resource
|
|
9
|
-
class="size-3.5 mr-1"
|
|
9
|
+
class="size-3.5 mr-1 shrink-0 translate-y-px"
|
|
10
10
|
/>
|
|
11
11
|
<span class="line-clamp-2">{{ resource.title || t('Fichier sans nom') }}</span>
|
|
12
12
|
</h3>
|
|
13
|
+
<ResourceSelector
|
|
14
|
+
v-if="resources && resources.length > 1"
|
|
15
|
+
:resources
|
|
16
|
+
:selected-id="resource.id"
|
|
17
|
+
@select="emit('select', $event)"
|
|
18
|
+
/>
|
|
13
19
|
<CopyButton
|
|
14
20
|
:label="t('Copier le lien')"
|
|
15
21
|
:copied-label="t('Lien copié !')"
|
|
16
22
|
:text="resourceExternalUrl"
|
|
23
|
+
class="hidden md:inline-flex"
|
|
17
24
|
/>
|
|
18
25
|
</div>
|
|
19
|
-
<div class="text-gray-medium text-xs flex items-center gap-1">
|
|
26
|
+
<div class="text-gray-medium text-xs flex items-center gap-1 flex-wrap">
|
|
20
27
|
<SchemaBadge :resource />
|
|
21
28
|
<RiSubtractLine
|
|
22
|
-
v-if="resource.schema"
|
|
29
|
+
v-if="resource.schema?.name || resource.schema?.url"
|
|
23
30
|
aria-hidden="true"
|
|
24
31
|
class="size-3 fill-gray-medium"
|
|
25
32
|
/>
|
|
@@ -115,6 +122,11 @@
|
|
|
115
122
|
v-if="ogcWms"
|
|
116
123
|
:resource="resource"
|
|
117
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>
|
|
118
130
|
</div>
|
|
119
131
|
<div v-if="tab.key === 'data'">
|
|
120
132
|
<JsonPreview
|
|
@@ -129,21 +141,36 @@
|
|
|
129
141
|
v-else-if="resource.format && resource.format.toLowerCase() === 'xml'"
|
|
130
142
|
:resource="resource"
|
|
131
143
|
/>
|
|
144
|
+
<ImagePreview
|
|
145
|
+
v-else-if="isImagePreviewFormat(resource.format)"
|
|
146
|
+
:resource="resource"
|
|
147
|
+
/>
|
|
132
148
|
<DatafairPreview
|
|
133
149
|
v-else-if="hasDatafairPreview"
|
|
134
150
|
:resource="resource"
|
|
135
151
|
:dataset="dataset"
|
|
136
152
|
/>
|
|
137
|
-
<
|
|
153
|
+
<OpenApiViewer
|
|
138
154
|
v-else-if="hasOpenAPIPreview"
|
|
139
155
|
:url="resource.extras['apidocUrl'] as string"
|
|
140
156
|
/>
|
|
141
|
-
<
|
|
157
|
+
<TabularExplorer
|
|
142
158
|
v-else-if="hasTabularData"
|
|
143
|
-
:resource="resource"
|
|
159
|
+
:resource-id="resource.id"
|
|
144
160
|
/>
|
|
145
161
|
<PreviewUnavailable v-else>
|
|
146
|
-
|
|
162
|
+
<!-- "File too large to download" is the only analysis:error value from hydra for now -->
|
|
163
|
+
<template v-if="resource.extras['analysis:error'] === 'File too large to download'">
|
|
164
|
+
{{ t("Ce fichier est trop volumineux pour être analysé et prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.") }}
|
|
165
|
+
</template>
|
|
166
|
+
<template v-else-if="resource.extras['analysis:parsing:error']">
|
|
167
|
+
{{ t("L'analyse de ce fichier a rencontré une erreur, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.") }}
|
|
168
|
+
<br>
|
|
169
|
+
<span class="text-gray-medium text-xs">{{ resource.extras['analysis:parsing:error'] }}</span>
|
|
170
|
+
</template>
|
|
171
|
+
<template v-else>
|
|
172
|
+
{{ t("Ce fichier ne peut pas être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.") }}
|
|
173
|
+
</template>
|
|
147
174
|
</PreviewUnavailable>
|
|
148
175
|
</div>
|
|
149
176
|
<div v-if="tab.key === 'description'">
|
|
@@ -162,137 +189,22 @@
|
|
|
162
189
|
<Metadata :resource />
|
|
163
190
|
</div>
|
|
164
191
|
<div v-if="tab.key === 'downloads'">
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
>
|
|
170
|
-
{{ t("URL d'origine") }}
|
|
171
|
-
</dt>
|
|
172
|
-
<dt
|
|
173
|
-
v-else
|
|
174
|
-
class="font-bold fr-text--sm fr-mb-0"
|
|
175
|
-
>
|
|
176
|
-
{{ t('Format original') }}
|
|
177
|
-
</dt>
|
|
178
|
-
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
|
|
179
|
-
<span
|
|
180
|
-
v-if="resource.format === 'url'"
|
|
181
|
-
class="inline-flex items-center max-w-full"
|
|
182
|
-
>
|
|
183
|
-
<a
|
|
184
|
-
:href="resource.latest"
|
|
185
|
-
class="fr-link no-icon-after truncate"
|
|
186
|
-
rel="ugc nofollow noopener"
|
|
187
|
-
target="_blank"
|
|
188
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
|
|
189
|
-
>
|
|
190
|
-
{{ resource.url }}
|
|
191
|
-
</a>
|
|
192
|
-
<span class="fr-ml-1v fr-icon-external-link-line fr-icon--sm shrink-0" />
|
|
193
|
-
</span>
|
|
194
|
-
<span v-else>
|
|
195
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
196
|
-
<a
|
|
197
|
-
:href="resource.latest"
|
|
198
|
-
class="fr-link"
|
|
199
|
-
rel="ugc nofollow noopener"
|
|
200
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${resource.format}`)"
|
|
201
|
-
>
|
|
202
|
-
<span>{{ t('Format {format}', { format: resource.format }) }}<span v-if="resourceFilesize"> - {{ filesize(resourceFilesize) }}</span></span>
|
|
203
|
-
</a>
|
|
204
|
-
</span>
|
|
205
|
-
<CopyButton
|
|
206
|
-
:label="t('Copier le lien')"
|
|
207
|
-
:copied-label="t('Lien copié !')"
|
|
208
|
-
:text="resource.latest"
|
|
209
|
-
class="relative"
|
|
210
|
-
/>
|
|
211
|
-
</dd>
|
|
212
|
-
<template v-if="generatedFormats.length">
|
|
213
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
214
|
-
{{ t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
|
|
215
|
-
</dt>
|
|
216
|
-
<dd
|
|
217
|
-
v-for="generatedFormat in generatedFormats"
|
|
218
|
-
:key="generatedFormat.format"
|
|
219
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
220
|
-
>
|
|
221
|
-
<span>
|
|
222
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
223
|
-
<a
|
|
224
|
-
:href="generatedFormat.url"
|
|
225
|
-
class="fr-link"
|
|
226
|
-
rel="ugc nofollow noopener"
|
|
227
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${generatedFormat.format}`)"
|
|
228
|
-
>
|
|
229
|
-
<span>{{ t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
|
|
230
|
-
</a>
|
|
231
|
-
</span>
|
|
232
|
-
<CopyButton
|
|
233
|
-
:label="t('Copier le lien')"
|
|
234
|
-
:copied-label="t('Lien copié !')"
|
|
235
|
-
:text="generatedFormat.url"
|
|
236
|
-
class="relative"
|
|
237
|
-
/>
|
|
238
|
-
</dd>
|
|
239
|
-
</template>
|
|
240
|
-
<template v-if="wfsFormats.length">
|
|
241
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
242
|
-
<div class="flex gap-1 items-center">
|
|
243
|
-
{{ t('Formats exportés depuis le service WFS') }}
|
|
244
|
-
<span v-if="defaultWfsProjection"> ({{ t('projection {crs}', { crs: defaultWfsProjection }) }})</span>
|
|
245
|
-
<Tooltip>
|
|
246
|
-
<RiInformationLine
|
|
247
|
-
class="flex-none size-4"
|
|
248
|
-
:aria-label="t(`Le lien de téléchargement interroge directement le flux WFS distant. Le nombre de features téléchargées peut être limité.`)"
|
|
249
|
-
aria-hidden="true"
|
|
250
|
-
/>
|
|
251
|
-
<template #tooltip>
|
|
252
|
-
<p class="text-sm font-normal mb-0">
|
|
253
|
-
{{ t(`Le lien de téléchargement interroge directement le flux WFS distant.`) }}
|
|
254
|
-
</p>
|
|
255
|
-
<p class="text-sm font-normal mb-0">
|
|
256
|
-
{{ t(`Le nombre de features téléchargées peut être limité.`) }}
|
|
257
|
-
</p>
|
|
258
|
-
</template>
|
|
259
|
-
</Tooltip>
|
|
260
|
-
</div>
|
|
261
|
-
</dt>
|
|
262
|
-
<dd
|
|
263
|
-
v-for="wfsFormat in wfsFormats"
|
|
264
|
-
:key="wfsFormat.format"
|
|
265
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
266
|
-
>
|
|
267
|
-
<span>
|
|
268
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
269
|
-
<a
|
|
270
|
-
:href="wfsFormat.url"
|
|
271
|
-
class="fr-link"
|
|
272
|
-
rel="ugc nofollow noopener"
|
|
273
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${wfsFormat.format}`)"
|
|
274
|
-
>
|
|
275
|
-
<span>{{ t('Format {format}', { format: wfsFormat.format }) }}</span>
|
|
276
|
-
</a>
|
|
277
|
-
</span>
|
|
278
|
-
<CopyButton
|
|
279
|
-
:label="t('Copier le lien')"
|
|
280
|
-
:copied-label="t('Lien copié !')"
|
|
281
|
-
:text="wfsFormat.url"
|
|
282
|
-
class="relative"
|
|
283
|
-
/>
|
|
284
|
-
</dd>
|
|
285
|
-
</template>
|
|
286
|
-
</dl>
|
|
192
|
+
<Downloads
|
|
193
|
+
:resource="resource"
|
|
194
|
+
:dataset="dataset"
|
|
195
|
+
/>
|
|
287
196
|
</div>
|
|
288
|
-
<div v-if="tab.key === '
|
|
197
|
+
<div v-if="tab.key === 'api'">
|
|
289
198
|
<div class="fr-mb-4w">
|
|
290
199
|
<p>{{ t("Cette API est générée automatiquement par {platform} à partir du fichier.", { platform: config.name }) }}</p>
|
|
291
200
|
<p>{{ t("- Si le fichier est modifié, l'API sera mise à jour et sa structure pourra changer.") }}</p>
|
|
292
201
|
<p>{{ t("- Si le fichier est supprimé, l'API sera également supprimée.") }}</p>
|
|
293
202
|
<p>{{ t("Pour des usages pérennes, prévoyez que cette API dépend directement du fichier source.") }}</p>
|
|
203
|
+
<p v-if="config.tabularApiUrl">
|
|
204
|
+
{{ t("L'URL de base de l'API est {url}", { url: config.tabularApiUrl }) }}
|
|
205
|
+
</p>
|
|
294
206
|
</div>
|
|
295
|
-
<
|
|
207
|
+
<OpenApiViewer
|
|
296
208
|
v-if="hasTabularData"
|
|
297
209
|
:url="`${config.tabularApiUrl}/api/resources/${resource.id}/swagger/`"
|
|
298
210
|
/>
|
|
@@ -306,32 +218,33 @@
|
|
|
306
218
|
|
|
307
219
|
<script setup lang="ts">
|
|
308
220
|
import { computed, defineAsyncComponent } from 'vue'
|
|
309
|
-
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine,
|
|
221
|
+
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
|
|
310
222
|
import PreviewUnavailable from '../ResourceAccordion/PreviewUnavailable.vue'
|
|
311
223
|
import { toast } from 'vue-sonner'
|
|
312
224
|
import BrandedButton from '../BrandedButton.vue'
|
|
313
225
|
import CopyButton from '../CopyButton.vue'
|
|
314
226
|
import MarkdownViewer from '../MarkdownViewer.vue'
|
|
315
227
|
import ResourceIcon from '../ResourceAccordion/ResourceIcon.vue'
|
|
316
|
-
import
|
|
228
|
+
import OpenApiViewer from '../OpenApiViewer/OpenApiViewer.vue'
|
|
317
229
|
import TabGroup from '../Tabs/TabGroup.vue'
|
|
318
230
|
import TabList from '../Tabs/TabList.vue'
|
|
319
231
|
import Tab from '../Tabs/Tab.vue'
|
|
320
232
|
import TabPanels from '../Tabs/TabPanels.vue'
|
|
321
233
|
import TabPanel from '../Tabs/TabPanel.vue'
|
|
322
|
-
import
|
|
323
|
-
import Preview from '../ResourceAccordion/Preview.vue'
|
|
234
|
+
import TabularExplorer from '../TabularExplorer/TabularExplorer.vue'
|
|
324
235
|
import DataStructure from '../ResourceAccordion/DataStructure.vue'
|
|
236
|
+
import Downloads from '../ResourceAccordion/Downloads.vue'
|
|
325
237
|
import Metadata from '../ResourceAccordion/Metadata.vue'
|
|
326
238
|
import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
|
|
239
|
+
import ResourceSelector from './ResourceSelector.vue'
|
|
327
240
|
import { filesize, summarize } from '../../functions/helpers'
|
|
328
|
-
import { getResourceFormatIcon } from '../../functions/resources'
|
|
329
|
-
import { getResourceExternalUrl, getResourceFilesize } from '../../functions/datasets'
|
|
241
|
+
import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize, isImagePreviewFormat } from '../../functions/resources'
|
|
330
242
|
import { trackEvent } from '../../functions/matomo'
|
|
331
243
|
import { useComponentsConfig } from '../../config'
|
|
332
244
|
import { useFormatDate } from '../../functions/dates'
|
|
333
245
|
import { useTranslation } from '../../composables/useTranslation'
|
|
334
246
|
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
|
|
247
|
+
import { provideTabularProfile } from '../../composables/useTabularProfile'
|
|
335
248
|
import type { Resource } from '../../types/resources'
|
|
336
249
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
337
250
|
|
|
@@ -344,6 +257,9 @@ const PdfPreview = defineAsyncComponent(() =>
|
|
|
344
257
|
const XmlPreview = defineAsyncComponent(() =>
|
|
345
258
|
import('../ResourceAccordion/XmlPreview.client.vue'),
|
|
346
259
|
)
|
|
260
|
+
const ImagePreview = defineAsyncComponent(() =>
|
|
261
|
+
import('../ResourceAccordion/ImagePreview.client.vue'),
|
|
262
|
+
)
|
|
347
263
|
const DatafairPreview = defineAsyncComponent(() =>
|
|
348
264
|
import('../ResourceAccordion/Datafair.client.vue'),
|
|
349
265
|
)
|
|
@@ -353,13 +269,15 @@ const MapContainer = defineAsyncComponent(() =>
|
|
|
353
269
|
const Pmtiles = defineAsyncComponent(() =>
|
|
354
270
|
import('../ResourceAccordion/Pmtiles.client.vue'),
|
|
355
271
|
)
|
|
356
|
-
const SwaggerClient = defineAsyncComponent(() =>
|
|
357
|
-
import('../ResourceAccordion/Swagger.client.vue'),
|
|
358
|
-
)
|
|
359
272
|
|
|
360
273
|
const props = defineProps<{
|
|
361
274
|
dataset: Dataset | DatasetV2
|
|
362
275
|
resource: Resource
|
|
276
|
+
resources?: Resource[]
|
|
277
|
+
}>()
|
|
278
|
+
|
|
279
|
+
const emit = defineEmits<{
|
|
280
|
+
select: [resource: Resource]
|
|
363
281
|
}>()
|
|
364
282
|
|
|
365
283
|
const { t } = useTranslation()
|
|
@@ -369,17 +287,19 @@ const { formatRelativeIfRecentDate } = useFormatDate()
|
|
|
369
287
|
const {
|
|
370
288
|
hasTabularData,
|
|
371
289
|
hasPmtiles,
|
|
290
|
+
hasPmtilesError,
|
|
291
|
+
pmtilesError,
|
|
372
292
|
hasDatafairPreview,
|
|
373
293
|
hasOpenAPIPreview,
|
|
374
294
|
ogcService,
|
|
375
295
|
ogcWms,
|
|
376
|
-
generatedFormats,
|
|
377
|
-
wfsFormats,
|
|
378
|
-
defaultWfsProjection,
|
|
379
296
|
isResourceUrl,
|
|
380
297
|
tabsOptions,
|
|
381
298
|
} = useResourceCapabilities(() => props.resource, () => props.dataset)
|
|
382
299
|
|
|
300
|
+
// Share the tabular profile fetch between TabularExplorer and DataStructure tabs.
|
|
301
|
+
await provideTabularProfile(() => props.resource.id)
|
|
302
|
+
|
|
383
303
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
384
304
|
const resourceExternalUrl = computed(() => getResourceExternalUrl(props.dataset, props.resource))
|
|
385
305
|
|
|
@@ -393,10 +313,6 @@ const downloadButtonTitle = computed(() => {
|
|
|
393
313
|
return t('Télécharger le fichier en {format}', { format: format.value })
|
|
394
314
|
})
|
|
395
315
|
|
|
396
|
-
const conversionsLastUpdate = computed(() =>
|
|
397
|
-
formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined),
|
|
398
|
-
)
|
|
399
|
-
|
|
400
316
|
const copyResourceUrl = async () => {
|
|
401
317
|
try {
|
|
402
318
|
await navigator.clipboard.writeText(props.resource.url)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Popover
|
|
3
|
+
v-slot="{ open, close }"
|
|
4
|
+
class="relative inline-block"
|
|
5
|
+
>
|
|
6
|
+
<slot
|
|
7
|
+
name="trigger"
|
|
8
|
+
:open="open"
|
|
9
|
+
>
|
|
10
|
+
<PopoverButton
|
|
11
|
+
class="inline-flex items-center justify-center size-6 rounded text-gray-plain hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-new-primary"
|
|
12
|
+
:aria-label="t('Choisir une autre ressource')"
|
|
13
|
+
>
|
|
14
|
+
<RiArrowDownSLine
|
|
15
|
+
class="size-4"
|
|
16
|
+
:class="{ 'rotate-180': open }"
|
|
17
|
+
aria-hidden="true"
|
|
18
|
+
/>
|
|
19
|
+
</PopoverButton>
|
|
20
|
+
</slot>
|
|
21
|
+
<PopoverPanel
|
|
22
|
+
:class="searchable
|
|
23
|
+
? 'absolute left-0 top-full z-50 mt-2 w-96 max-w-[calc(100vw-2rem)] bg-white border border-gray-default rounded shadow-lg p-3 space-y-2'
|
|
24
|
+
: 'absolute left-0 top-full z-50 mt-1 w-80 max-h-96 overflow-auto bg-white border border-gray-default rounded shadow-lg p-1'"
|
|
25
|
+
>
|
|
26
|
+
<input
|
|
27
|
+
v-if="searchable"
|
|
28
|
+
v-model="searchQuery"
|
|
29
|
+
type="search"
|
|
30
|
+
class="w-full border border-gray-default rounded px-2.5 py-1.5 text-sm"
|
|
31
|
+
:placeholder="t('Rechercher dans les ressources…')"
|
|
32
|
+
>
|
|
33
|
+
<ul
|
|
34
|
+
v-if="filteredResources.length > 0"
|
|
35
|
+
class="list-none p-0 m-0 space-y-0.5 max-h-80 overflow-y-auto"
|
|
36
|
+
>
|
|
37
|
+
<li
|
|
38
|
+
v-for="r in filteredResources"
|
|
39
|
+
:key="r.id"
|
|
40
|
+
>
|
|
41
|
+
<button
|
|
42
|
+
v-if="!isDisabled?.(r)"
|
|
43
|
+
type="button"
|
|
44
|
+
class="flex items-center gap-1.5 w-full text-left px-2 py-1.5 rounded text-sm hover:bg-gray-100 focus:outline-none focus-visible:bg-gray-100"
|
|
45
|
+
:class="{ 'font-bold bg-blue-50 text-new-primary': r.id === selectedId }"
|
|
46
|
+
@click="emit('select', r); close()"
|
|
47
|
+
>
|
|
48
|
+
<ResourceIcon
|
|
49
|
+
:resource="r"
|
|
50
|
+
class="size-3.5 shrink-0"
|
|
51
|
+
/>
|
|
52
|
+
<span class="truncate">{{ r.title || t('Fichier sans nom') }}</span>
|
|
53
|
+
<span
|
|
54
|
+
v-if="r.format"
|
|
55
|
+
class="ml-auto text-xs text-gray-medium uppercase shrink-0"
|
|
56
|
+
>
|
|
57
|
+
{{ r.format }}
|
|
58
|
+
</span>
|
|
59
|
+
</button>
|
|
60
|
+
<div
|
|
61
|
+
v-else
|
|
62
|
+
class="flex items-center gap-1.5 px-2 py-1.5 rounded text-sm text-gray-medium cursor-not-allowed"
|
|
63
|
+
:title="disabledTitle"
|
|
64
|
+
>
|
|
65
|
+
<ResourceIcon
|
|
66
|
+
:resource="r"
|
|
67
|
+
class="size-3.5 shrink-0 opacity-50"
|
|
68
|
+
/>
|
|
69
|
+
<span class="truncate opacity-70">{{ r.title || t('Fichier sans nom') }}</span>
|
|
70
|
+
</div>
|
|
71
|
+
</li>
|
|
72
|
+
</ul>
|
|
73
|
+
<p
|
|
74
|
+
v-else
|
|
75
|
+
class="text-sm text-gray-medium italic mb-0 px-2 py-2"
|
|
76
|
+
>
|
|
77
|
+
{{ t('Aucune ressource correspondante') }}
|
|
78
|
+
</p>
|
|
79
|
+
</PopoverPanel>
|
|
80
|
+
</Popover>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script setup lang="ts">
|
|
84
|
+
import { computed, ref } from 'vue'
|
|
85
|
+
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
|
86
|
+
import { RiArrowDownSLine } from '@remixicon/vue'
|
|
87
|
+
import { useTranslation } from '../../composables/useTranslation'
|
|
88
|
+
import ResourceIcon from '../ResourceAccordion/ResourceIcon.vue'
|
|
89
|
+
import type { Resource } from '../../types/resources'
|
|
90
|
+
|
|
91
|
+
const props = defineProps<{
|
|
92
|
+
resources: Resource[]
|
|
93
|
+
selectedId: string
|
|
94
|
+
searchable?: boolean
|
|
95
|
+
isDisabled?: (resource: Resource) => boolean
|
|
96
|
+
disabledTitle?: string
|
|
97
|
+
}>()
|
|
98
|
+
|
|
99
|
+
const emit = defineEmits<{
|
|
100
|
+
select: [resource: Resource]
|
|
101
|
+
}>()
|
|
102
|
+
|
|
103
|
+
const { t } = useTranslation()
|
|
104
|
+
|
|
105
|
+
const searchQuery = ref('')
|
|
106
|
+
|
|
107
|
+
const filteredResources = computed(() => {
|
|
108
|
+
if (!props.searchable) return props.resources
|
|
109
|
+
const q = searchQuery.value.trim().toLowerCase()
|
|
110
|
+
if (!q) return props.resources
|
|
111
|
+
return props.resources.filter(r => (r.title ?? '').toLowerCase().includes(q))
|
|
112
|
+
})
|
|
113
|
+
</script>
|
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
<article class="fr-enlarge-link group/reuse-card bg-white border border-gray-default hover:bg-gray-some flex flex-col relative">
|
|
3
3
|
<div class="flex flex-col h-full flex-1 order-2 px-8">
|
|
4
4
|
<div class="order-1 flex flex-col px-4 py-1 h-full -mx-8">
|
|
5
|
-
<
|
|
5
|
+
<component
|
|
6
|
+
:is="titleTag"
|
|
7
|
+
class="font-bold text-base mt-1 mb-0 truncate"
|
|
8
|
+
>
|
|
6
9
|
<AppLink
|
|
7
10
|
class="text-gray-title overflow-hidden"
|
|
8
11
|
:to="reuseUrl"
|
|
9
12
|
>
|
|
10
13
|
{{ reuse.title }}
|
|
11
14
|
</AppLink>
|
|
12
|
-
</
|
|
15
|
+
</component>
|
|
13
16
|
<div class="order-3 text-sm m-0 text-gray-medium">
|
|
14
17
|
<div class="text-sm mb-0 flex items-center">
|
|
15
18
|
<ObjectCardOwner
|
|
@@ -65,15 +68,16 @@ import { RiLockLine, RiSubtractLine } from '@remixicon/vue'
|
|
|
65
68
|
import { computed } from 'vue'
|
|
66
69
|
import type { RouteLocationRaw } from 'vue-router'
|
|
67
70
|
import { useFormatDate } from '../functions/dates'
|
|
68
|
-
import type { Reuse } from '../types/reuses'
|
|
71
|
+
import type { Reuse, ReuseV2 } from '../types/reuses'
|
|
72
|
+
import type { TitleTag } from '../types/ui'
|
|
69
73
|
import { useTranslation } from '../composables/useTranslation'
|
|
70
74
|
import AppLink from './AppLink.vue'
|
|
71
75
|
import ObjectCardOwner from './ObjectCardOwner.vue'
|
|
72
76
|
import ReuseDetails from './ReuseDetails.vue'
|
|
73
77
|
import Placeholder from './Placeholder.vue'
|
|
74
78
|
|
|
75
|
-
const props = defineProps<{
|
|
76
|
-
reuse: Reuse
|
|
79
|
+
const props = withDefaults(defineProps<{
|
|
80
|
+
reuse: Reuse | ReuseV2
|
|
77
81
|
|
|
78
82
|
/**
|
|
79
83
|
* The reuseUrl is a route location object to allow Vue Router to navigate to the details of a reuse.
|
|
@@ -86,7 +90,11 @@ const props = defineProps<{
|
|
|
86
90
|
* It is used as a separate prop to allow other sites using the package to define their own organization pages.
|
|
87
91
|
*/
|
|
88
92
|
organizationUrl?: RouteLocationRaw
|
|
89
|
-
|
|
93
|
+
|
|
94
|
+
titleTag?: TitleTag
|
|
95
|
+
}>(), {
|
|
96
|
+
titleTag: 'h3',
|
|
97
|
+
})
|
|
90
98
|
|
|
91
99
|
const { t } = useTranslation()
|
|
92
100
|
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
@@ -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 } from '../types/reuses'
|
|
35
|
+
import type { Reuse, ReuseV2 } from '../types/reuses'
|
|
36
36
|
import { useTranslation } from '../composables/useTranslation'
|
|
37
37
|
|
|
38
38
|
const props = defineProps<{
|
|
39
|
-
reuse: Reuse
|
|
39
|
+
reuse: Reuse | ReuseV2
|
|
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 } from '../types/reuses'
|
|
63
|
+
import type { Reuse, ReuseV2 } 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
|
|
74
|
+
reuse: Reuse | ReuseV2
|
|
75
75
|
reuseUrl?: RouteLocationRaw
|
|
76
76
|
organizationUrl?: RouteLocationRaw
|
|
77
77
|
}>()
|