@datagouv/components-next 1.0.2-dev.10 → 1.0.2-dev.100
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/assets/main.css +4 -0
- package/dist/{Control-DuZJdKV_.js → Control-ZFh5ta_U.js} +1 -1
- package/dist/Datafair.client-C2j760M5.js +30 -0
- package/dist/{Event--kp8kMdJ.js → Event-DSQcW7OF.js} +24 -24
- package/dist/{Image-34hvypZI.js → Image-BijNEG0p.js} +6 -6
- package/dist/JsonPreview.client-PFfBR4J8.js +40 -0
- package/dist/{Map-BjUnLyj8.js → Map-BUtPf5GN.js} +756 -756
- package/dist/MapContainer.client-CGrS2baS.js +101 -0
- package/dist/{OSM-s40W6sQ2.js → OSM-D4MTdBtk.js} +2 -2
- package/dist/{PdfPreview.client-BVjPxlPu.js → PdfPreview.client-DU36UBGQ.js} +822 -865
- package/dist/{Pmtiles.client-CRJ56yX2.js → Pmtiles.client-DuTezcn5.js} +574 -579
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-ProPRqX6.js +61 -0
- package/dist/{ScaleLine-KW-nXqp3.js → ScaleLine-hJQIqcZm.js} +2 -2
- package/dist/{Tile-DbNFNPfU.js → Tile-Dcl7oIVu.js} +35 -35
- package/dist/{TileImage-BsXBxMtq.js → TileImage-BJeHipMX.js} +4 -4
- package/dist/{View-BR92hTWP.js → View-xp_P_OHw.js} +412 -401
- package/dist/XmlPreview.client-Bcq2Ye14.js +34 -0
- package/dist/{common-PJfpC179.js → common-BjQlan3k.js} +36 -36
- package/dist/components-next.css +6 -6
- package/dist/components-next.js +175 -149
- package/dist/components.css +1 -1
- package/dist/{index-BZsAZ7iw.js → index-BJ-zwAF5.js} +32886 -27183
- package/dist/{main-qc4CO9Kn.js → main-TqHFAOCi.js} +92255 -76685
- package/dist/{proj-DsetBcW7.js → proj-CsNo9yH1.js} +532 -512
- package/dist/{tilecoord-Db24Px13.js → tilecoord-A0fLnBZr.js} +28 -28
- package/dist/{vue3-xml-viewer.common-CCOV_ohP.js → vue3-xml-viewer.common-BnJTx_B7.js} +1 -1
- package/package.json +18 -11
- package/src/components/ActivityList/ActivityList.vue +0 -2
- package/src/components/Chart/ChartViewer.vue +226 -0
- package/src/components/Chart/ChartViewerWrapper.vue +170 -0
- package/src/components/DataserviceCard.vue +3 -0
- package/src/components/DatasetCard.vue +9 -4
- package/src/components/Form/Listbox.vue +101 -0
- package/src/components/Form/SearchableSelect.vue +2 -1
- 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/ReadMore.vue +1 -1
- package/src/components/ResourceAccordion/DataStructure.vue +11 -33
- package/src/components/ResourceAccordion/Datafair.client.vue +4 -10
- package/src/components/ResourceAccordion/Downloads.vue +160 -0
- package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -121
- package/src/components/ResourceAccordion/MapContainer.client.vue +5 -14
- package/src/components/ResourceAccordion/Metadata.vue +1 -2
- package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -103
- package/src/components/ResourceAccordion/Pmtiles.client.vue +5 -10
- package/src/components/ResourceAccordion/Preview.vue +16 -21
- package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
- package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
- package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +10 -109
- package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -115
- package/src/components/ResourceExplorer/ResourceExplorer.vue +35 -20
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +56 -146
- package/src/components/ResourceExplorer/ResourceSelector.vue +113 -0
- package/src/components/ReuseCard.vue +12 -4
- package/src/components/Search/GlobalSearch.vue +191 -110
- package/src/components/Search/SearchInput.vue +5 -4
- package/src/components/TabularExplorer/TabularCell.vue +51 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +973 -0
- package/src/components/TabularExplorer/TabularFilterContent.vue +351 -0
- package/src/components/TabularExplorer/TabularFilterPopover.vue +111 -0
- package/src/components/TabularExplorer/types.ts +83 -0
- package/src/composables/useHasTabularData.ts +13 -0
- package/src/composables/useMetrics.ts +1 -1
- package/src/composables/useResourceCapabilities.ts +1 -1
- package/src/composables/useSearchFilter.ts +118 -0
- package/src/composables/useStableQueryParams.ts +31 -3
- package/src/composables/useTabularProfile.ts +70 -0
- package/src/config.ts +20 -3
- package/src/functions/api.ts +9 -37
- package/src/functions/api.types.ts +1 -0
- package/src/functions/charts.ts +68 -0
- package/src/functions/datasets.ts +0 -17
- package/src/functions/metrics.ts +6 -4
- package/src/functions/resources.ts +56 -1
- package/src/functions/tabular.ts +60 -0
- package/src/functions/tabularApi.ts +138 -11
- package/src/main.ts +94 -7
- package/src/types/dataservices.ts +2 -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/search.ts +52 -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 +89 -0
- package/assets/swagger-themes/newspaper.css +0 -1670
- package/dist/Datafair.client-0UYUu5yf.js +0 -35
- package/dist/JsonPreview.client-BrTMBWHZ.js +0 -87
- package/dist/MapContainer.client-CUmKyByc.js +0 -107
- package/dist/Swagger.client-2Yn7iF0A.js +0 -4
- package/dist/XmlPreview.client-DxqlVnKu.js +0 -79
- package/src/components/ResourceAccordion/Swagger.client.vue +0 -48
- package/src/functions/pagination.ts +0 -9
- /package/assets/illustrations/{_microscope.svg → microscope.svg} +0 -0
|
@@ -2,21 +2,34 @@
|
|
|
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">
|
|
27
|
+
<SchemaBadge :resource />
|
|
28
|
+
<RiSubtractLine
|
|
29
|
+
v-if="resource.schema?.name || resource.schema?.url"
|
|
30
|
+
aria-hidden="true"
|
|
31
|
+
class="size-3 fill-gray-medium"
|
|
32
|
+
/>
|
|
20
33
|
<span>{{ t('mis à jour {date}', { date: formatRelativeIfRecentDate(resource.last_modified) }) }}</span>
|
|
21
34
|
<RiSubtractLine
|
|
22
35
|
aria-hidden="true"
|
|
@@ -128,14 +141,28 @@
|
|
|
128
141
|
:resource="resource"
|
|
129
142
|
:dataset="dataset"
|
|
130
143
|
/>
|
|
131
|
-
<
|
|
144
|
+
<OpenApiViewer
|
|
132
145
|
v-else-if="hasOpenAPIPreview"
|
|
133
146
|
:url="resource.extras['apidocUrl'] as string"
|
|
134
147
|
/>
|
|
135
|
-
<
|
|
136
|
-
v-else
|
|
137
|
-
:resource="resource"
|
|
148
|
+
<TabularExplorer
|
|
149
|
+
v-else-if="hasTabularData"
|
|
150
|
+
:resource-id="resource.id"
|
|
138
151
|
/>
|
|
152
|
+
<PreviewUnavailable v-else>
|
|
153
|
+
<!-- "File too large to download" is the only analysis:error value from hydra for now -->
|
|
154
|
+
<template v-if="resource.extras['analysis:error'] === 'File too large to download'">
|
|
155
|
+
{{ t("Ce fichier est trop volumineux pour être analysé et prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.") }}
|
|
156
|
+
</template>
|
|
157
|
+
<template v-else-if="resource.extras['analysis:parsing:error']">
|
|
158
|
+
{{ 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.") }}
|
|
159
|
+
<br>
|
|
160
|
+
<span class="text-gray-medium text-xs">{{ resource.extras['analysis:parsing:error'] }}</span>
|
|
161
|
+
</template>
|
|
162
|
+
<template v-else>
|
|
163
|
+
{{ t("Ce fichier ne peut pas être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.") }}
|
|
164
|
+
</template>
|
|
165
|
+
</PreviewUnavailable>
|
|
139
166
|
</div>
|
|
140
167
|
<div v-if="tab.key === 'description'">
|
|
141
168
|
<MarkdownViewer
|
|
@@ -153,128 +180,10 @@
|
|
|
153
180
|
<Metadata :resource />
|
|
154
181
|
</div>
|
|
155
182
|
<div v-if="tab.key === 'downloads'">
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
>
|
|
161
|
-
{{ t("URL d'origine") }}
|
|
162
|
-
</dt>
|
|
163
|
-
<dt
|
|
164
|
-
v-else
|
|
165
|
-
class="font-bold fr-text--sm fr-mb-0"
|
|
166
|
-
>
|
|
167
|
-
{{ t('Format original') }}
|
|
168
|
-
</dt>
|
|
169
|
-
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
|
|
170
|
-
<span
|
|
171
|
-
v-if="resource.format === 'url'"
|
|
172
|
-
class="inline-flex items-center max-w-full"
|
|
173
|
-
>
|
|
174
|
-
<a
|
|
175
|
-
:href="resource.latest"
|
|
176
|
-
class="fr-link no-icon-after truncate"
|
|
177
|
-
rel="ugc nofollow noopener"
|
|
178
|
-
target="_blank"
|
|
179
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
|
|
180
|
-
>
|
|
181
|
-
{{ resource.url }}
|
|
182
|
-
</a>
|
|
183
|
-
<span class="fr-ml-1v fr-icon-external-link-line fr-icon--sm shrink-0" />
|
|
184
|
-
</span>
|
|
185
|
-
<span v-else>
|
|
186
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
187
|
-
<a
|
|
188
|
-
:href="resource.latest"
|
|
189
|
-
class="fr-link"
|
|
190
|
-
rel="ugc nofollow noopener"
|
|
191
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${resource.format}`)"
|
|
192
|
-
>
|
|
193
|
-
<span>{{ t('Format {format}', { format: resource.format }) }}<span v-if="resourceFilesize"> - {{ filesize(resourceFilesize) }}</span></span>
|
|
194
|
-
</a>
|
|
195
|
-
</span>
|
|
196
|
-
<CopyButton
|
|
197
|
-
:label="t('Copier le lien')"
|
|
198
|
-
:copied-label="t('Lien copié !')"
|
|
199
|
-
:text="resource.latest"
|
|
200
|
-
class="relative"
|
|
201
|
-
/>
|
|
202
|
-
</dd>
|
|
203
|
-
<template v-if="generatedFormats.length">
|
|
204
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
205
|
-
{{ t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
|
|
206
|
-
</dt>
|
|
207
|
-
<dd
|
|
208
|
-
v-for="generatedFormat in generatedFormats"
|
|
209
|
-
:key="generatedFormat.format"
|
|
210
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
211
|
-
>
|
|
212
|
-
<span>
|
|
213
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
214
|
-
<a
|
|
215
|
-
:href="generatedFormat.url"
|
|
216
|
-
class="fr-link"
|
|
217
|
-
rel="ugc nofollow noopener"
|
|
218
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${generatedFormat.format}`)"
|
|
219
|
-
>
|
|
220
|
-
<span>{{ t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
|
|
221
|
-
</a>
|
|
222
|
-
</span>
|
|
223
|
-
<CopyButton
|
|
224
|
-
:label="t('Copier le lien')"
|
|
225
|
-
:copied-label="t('Lien copié !')"
|
|
226
|
-
:text="generatedFormat.url"
|
|
227
|
-
class="relative"
|
|
228
|
-
/>
|
|
229
|
-
</dd>
|
|
230
|
-
</template>
|
|
231
|
-
<template v-if="wfsFormats.length">
|
|
232
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
233
|
-
<div class="flex gap-1 items-center">
|
|
234
|
-
{{ t('Formats exportés depuis le service WFS') }}
|
|
235
|
-
<span v-if="defaultWfsProjection"> ({{ t('projection {crs}', { crs: defaultWfsProjection }) }})</span>
|
|
236
|
-
<Tooltip>
|
|
237
|
-
<RiInformationLine
|
|
238
|
-
class="flex-none size-4"
|
|
239
|
-
: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é.`)"
|
|
240
|
-
aria-hidden="true"
|
|
241
|
-
/>
|
|
242
|
-
<template #tooltip>
|
|
243
|
-
<p class="text-sm font-normal mb-0">
|
|
244
|
-
{{ t(`Le lien de téléchargement interroge directement le flux WFS distant.`) }}
|
|
245
|
-
</p>
|
|
246
|
-
<p class="text-sm font-normal mb-0">
|
|
247
|
-
{{ t(`Le nombre de features téléchargées peut être limité.`) }}
|
|
248
|
-
</p>
|
|
249
|
-
</template>
|
|
250
|
-
</Tooltip>
|
|
251
|
-
</div>
|
|
252
|
-
</dt>
|
|
253
|
-
<dd
|
|
254
|
-
v-for="wfsFormat in wfsFormats"
|
|
255
|
-
:key="wfsFormat.format"
|
|
256
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
257
|
-
>
|
|
258
|
-
<span>
|
|
259
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
260
|
-
<a
|
|
261
|
-
:href="wfsFormat.url"
|
|
262
|
-
class="fr-link"
|
|
263
|
-
rel="ugc nofollow noopener"
|
|
264
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${wfsFormat.format}`)"
|
|
265
|
-
>
|
|
266
|
-
<span>{{ t('Format {format}', { format: wfsFormat.format }) }}</span>
|
|
267
|
-
</a>
|
|
268
|
-
</span>
|
|
269
|
-
<CopyButton
|
|
270
|
-
:label="t('Copier le lien')"
|
|
271
|
-
:copied-label="t('Lien copié !')"
|
|
272
|
-
:text="wfsFormat.url"
|
|
273
|
-
class="relative"
|
|
274
|
-
/>
|
|
275
|
-
</dd>
|
|
276
|
-
</template>
|
|
277
|
-
</dl>
|
|
183
|
+
<Downloads
|
|
184
|
+
:resource="resource"
|
|
185
|
+
:dataset="dataset"
|
|
186
|
+
/>
|
|
278
187
|
</div>
|
|
279
188
|
<div v-if="tab.key === 'swagger'">
|
|
280
189
|
<div class="fr-mb-4w">
|
|
@@ -283,7 +192,7 @@
|
|
|
283
192
|
<p>{{ t("- Si le fichier est supprimé, l'API sera également supprimée.") }}</p>
|
|
284
193
|
<p>{{ t("Pour des usages pérennes, prévoyez que cette API dépend directement du fichier source.") }}</p>
|
|
285
194
|
</div>
|
|
286
|
-
<
|
|
195
|
+
<OpenApiViewer
|
|
287
196
|
v-if="hasTabularData"
|
|
288
197
|
:url="`${config.tabularApiUrl}/api/resources/${resource.id}/swagger/`"
|
|
289
198
|
/>
|
|
@@ -297,30 +206,33 @@
|
|
|
297
206
|
|
|
298
207
|
<script setup lang="ts">
|
|
299
208
|
import { computed, defineAsyncComponent } from 'vue'
|
|
300
|
-
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine,
|
|
209
|
+
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
|
|
210
|
+
import PreviewUnavailable from '../ResourceAccordion/PreviewUnavailable.vue'
|
|
301
211
|
import { toast } from 'vue-sonner'
|
|
302
212
|
import BrandedButton from '../BrandedButton.vue'
|
|
303
213
|
import CopyButton from '../CopyButton.vue'
|
|
304
214
|
import MarkdownViewer from '../MarkdownViewer.vue'
|
|
305
215
|
import ResourceIcon from '../ResourceAccordion/ResourceIcon.vue'
|
|
306
|
-
import
|
|
216
|
+
import OpenApiViewer from '../OpenApiViewer/OpenApiViewer.vue'
|
|
307
217
|
import TabGroup from '../Tabs/TabGroup.vue'
|
|
308
218
|
import TabList from '../Tabs/TabList.vue'
|
|
309
219
|
import Tab from '../Tabs/Tab.vue'
|
|
310
220
|
import TabPanels from '../Tabs/TabPanels.vue'
|
|
311
221
|
import TabPanel from '../Tabs/TabPanel.vue'
|
|
312
|
-
import
|
|
313
|
-
import Preview from '../ResourceAccordion/Preview.vue'
|
|
222
|
+
import TabularExplorer from '../TabularExplorer/TabularExplorer.vue'
|
|
314
223
|
import DataStructure from '../ResourceAccordion/DataStructure.vue'
|
|
224
|
+
import Downloads from '../ResourceAccordion/Downloads.vue'
|
|
315
225
|
import Metadata from '../ResourceAccordion/Metadata.vue'
|
|
226
|
+
import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
|
|
227
|
+
import ResourceSelector from './ResourceSelector.vue'
|
|
316
228
|
import { filesize, summarize } from '../../functions/helpers'
|
|
317
|
-
import { getResourceFormatIcon } from '../../functions/resources'
|
|
318
|
-
import { getResourceExternalUrl, getResourceFilesize } from '../../functions/datasets'
|
|
229
|
+
import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
|
|
319
230
|
import { trackEvent } from '../../functions/matomo'
|
|
320
231
|
import { useComponentsConfig } from '../../config'
|
|
321
232
|
import { useFormatDate } from '../../functions/dates'
|
|
322
233
|
import { useTranslation } from '../../composables/useTranslation'
|
|
323
234
|
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
|
|
235
|
+
import { provideTabularProfile } from '../../composables/useTabularProfile'
|
|
324
236
|
import type { Resource } from '../../types/resources'
|
|
325
237
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
326
238
|
|
|
@@ -342,13 +254,15 @@ const MapContainer = defineAsyncComponent(() =>
|
|
|
342
254
|
const Pmtiles = defineAsyncComponent(() =>
|
|
343
255
|
import('../ResourceAccordion/Pmtiles.client.vue'),
|
|
344
256
|
)
|
|
345
|
-
const SwaggerClient = defineAsyncComponent(() =>
|
|
346
|
-
import('../ResourceAccordion/Swagger.client.vue'),
|
|
347
|
-
)
|
|
348
257
|
|
|
349
258
|
const props = defineProps<{
|
|
350
259
|
dataset: Dataset | DatasetV2
|
|
351
260
|
resource: Resource
|
|
261
|
+
resources?: Resource[]
|
|
262
|
+
}>()
|
|
263
|
+
|
|
264
|
+
const emit = defineEmits<{
|
|
265
|
+
select: [resource: Resource]
|
|
352
266
|
}>()
|
|
353
267
|
|
|
354
268
|
const { t } = useTranslation()
|
|
@@ -362,13 +276,13 @@ const {
|
|
|
362
276
|
hasOpenAPIPreview,
|
|
363
277
|
ogcService,
|
|
364
278
|
ogcWms,
|
|
365
|
-
generatedFormats,
|
|
366
|
-
wfsFormats,
|
|
367
|
-
defaultWfsProjection,
|
|
368
279
|
isResourceUrl,
|
|
369
280
|
tabsOptions,
|
|
370
281
|
} = useResourceCapabilities(() => props.resource, () => props.dataset)
|
|
371
282
|
|
|
283
|
+
// Share the tabular profile fetch between TabularExplorer and DataStructure tabs.
|
|
284
|
+
await provideTabularProfile(() => props.resource.id)
|
|
285
|
+
|
|
372
286
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
373
287
|
const resourceExternalUrl = computed(() => getResourceExternalUrl(props.dataset, props.resource))
|
|
374
288
|
|
|
@@ -382,10 +296,6 @@ const downloadButtonTitle = computed(() => {
|
|
|
382
296
|
return t('Télécharger le fichier en {format}', { format: format.value })
|
|
383
297
|
})
|
|
384
298
|
|
|
385
|
-
const conversionsLastUpdate = computed(() =>
|
|
386
|
-
formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined),
|
|
387
|
-
)
|
|
388
|
-
|
|
389
299
|
const copyResourceUrl = async () => {
|
|
390
300
|
try {
|
|
391
301
|
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
|
|
@@ -66,13 +69,14 @@ import { computed } from 'vue'
|
|
|
66
69
|
import type { RouteLocationRaw } from 'vue-router'
|
|
67
70
|
import { useFormatDate } from '../functions/dates'
|
|
68
71
|
import type { Reuse } 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<{
|
|
79
|
+
const props = withDefaults(defineProps<{
|
|
76
80
|
reuse: Reuse
|
|
77
81
|
|
|
78
82
|
/**
|
|
@@ -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()
|