@datagouv/components-next 1.0.2-dev.2 → 1.0.2-dev.200
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-CFTmBFoY.js +30 -0
- 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-BvDM3qjE.js +36 -0
- package/dist/JsonPreview.client-BP6gPRxf.js +40 -0
- package/dist/{Map-BjUnLyj8.js → Map-BfqKMw0S.js} +1739 -1599
- package/dist/MapContainer.client-D9N3664r.js +101 -0
- package/dist/{OSM-s40W6sQ2.js → OSM-CcrUhItr.js} +15 -23
- package/dist/{PdfPreview.client-C-w6-w44.js → PdfPreview.client-C6A6ZiKl.js} +835 -871
- package/dist/Pmtiles.client-B_sDZoqu.js +26333 -0
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-DGLXBys_.js +60 -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-DFQ1T-LN.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 +196 -150
- package/dist/components.css +2 -2
- package/dist/{index-SrYZwgCT.js → index-B_tPYi5Z.js} +34094 -27864
- package/dist/{leaflet-src-7m1mB8LI.js → leaflet-src-PeylHk0o.js} +162 -164
- package/dist/main-CVOZp_Nx.js +75398 -0
- 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-BRxsqI9j.js → vue3-xml-viewer.common-CcF3Xd23.js} +1 -1
- package/package.json +50 -37
- package/src/chart.ts +5 -0
- package/src/components/ActivityList/ActivityList.vue +24 -14
- package/src/components/AppLink.vue +3 -0
- package/src/components/BannerAction.vue +6 -2
- package/src/components/Chart/ChartViewer.vue +320 -0
- package/src/components/Chart/ChartViewerWrapper.vue +182 -0
- package/src/components/CopyButton.vue +6 -2
- package/src/components/DataserviceCard.vue +24 -5
- 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 +24 -9
- package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -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/DiscussionMessageCard.vue +14 -15
- package/src/components/Form/Listbox.vue +101 -0
- package/src/components/Form/SchemaSelect.vue +2 -0
- package/src/components/Form/SearchableSelect.vue +2 -1
- package/src/components/FormattedDate.vue +81 -0
- package/src/components/InfiniteLoader.vue +53 -0
- package/src/components/LoadingBlock.vue +4 -1
- 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 +25 -62
- package/src/components/PostCard.vue +13 -15
- package/src/components/RadioInput.vue +7 -2
- 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 +172 -0
- package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
- package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -121
- package/src/components/ResourceAccordion/MapContainer.client.vue +6 -19
- package/src/components/ResourceAccordion/Metadata.vue +4 -6
- package/src/components/ResourceAccordion/PdfPreview.client.vue +58 -113
- package/src/components/ResourceAccordion/PdfSkeleton.vue +44 -0
- package/src/components/ResourceAccordion/Pmtiles.client.vue +33 -23
- package/src/components/ResourceAccordion/Preview.vue +24 -25
- package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
- package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
- package/src/components/ResourceAccordion/PreviewWrapper.vue +89 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +36 -117
- package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -115
- package/src/components/ResourceExplorer/ResourceExplorer.vue +105 -199
- package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +79 -0
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +104 -71
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +143 -280
- package/src/components/ResourceExplorer/ResourceMainAction.vue +240 -0
- package/src/components/ResourceExplorer/ResourceSelector.vue +51 -0
- package/src/components/ResourceExplorer/ResourceViewerHeader.vue +122 -0
- package/src/components/ResourceExplorer/ResourceViewerSkeleton.vue +94 -0
- package/src/components/ResourceListItem.vue +168 -0
- package/src/components/ReuseCard.vue +28 -9
- package/src/components/ReuseDetails.vue +2 -2
- package/src/components/ReuseHorizontalCard.vue +2 -2
- package/src/components/SchemaCard.vue +10 -1
- package/src/components/Search/Filter/AccessTypeFilter.vue +2 -2
- package/src/components/Search/GlobalSearch.vue +229 -123
- package/src/components/Search/SearchInput.vue +5 -4
- package/src/components/Search/Sidemenu.vue +4 -3
- package/src/components/SmallChart.vue +11 -10
- package/src/components/StatBox.vue +13 -5
- package/src/components/TabularExplorer/TabularActiveFilters.vue +79 -0
- package/src/components/TabularExplorer/TabularCell.vue +50 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularColumnsMenu.vue +112 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +299 -0
- package/src/components/TabularExplorer/TabularFilterContent.vue +362 -0
- package/src/components/TabularExplorer/TabularFilterPopover.vue +106 -0
- package/src/components/TabularExplorer/TabularMobileFilterButton.vue +21 -0
- package/src/components/TabularExplorer/TabularMobileFilters.vue +150 -0
- package/src/components/TabularExplorer/TabularRowsInfo.vue +31 -0
- package/src/components/TabularExplorer/TabularSkeleton.vue +92 -0
- package/src/components/TabularExplorer/TabularTable.vue +481 -0
- package/src/components/TabularExplorer/TabularToolbar.vue +25 -0
- package/src/components/TabularExplorer/types.ts +84 -0
- package/src/components/TabularExplorer/useColumnMetadata.ts +98 -0
- package/src/components/TabularExplorer/useTabularContext.ts +82 -0
- package/src/components/TopicCard.vue +13 -14
- package/src/composables/useActiveDescendant.ts +5 -0
- package/src/composables/useDatasetResources.ts +164 -0
- package/src/composables/useHasTabularData.ts +15 -1
- package/src/composables/useMetrics.ts +1 -1
- package/src/composables/useResizable.ts +46 -0
- package/src/composables/useResourceCapabilities.ts +49 -41
- package/src/composables/useSearchFilter.ts +120 -0
- package/src/composables/useStableQueryParams.ts +38 -6
- package/src/composables/useTabularProfile.ts +70 -0
- package/src/composables/useTranslation.ts +24 -9
- 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 +6 -7
- package/src/functions/helpers.ts +15 -0
- package/src/functions/metrics.ts +63 -60
- package/src/functions/paginate.ts +46 -0
- package/src/functions/resourceCapabilities.ts +34 -0
- package/src/functions/resources.ts +136 -1
- package/src/functions/schemas.ts +27 -0
- package/src/functions/scroll.ts +20 -0
- package/src/functions/tabular.ts +214 -0
- package/src/functions/tabularApi.ts +96 -11
- package/src/main.ts +119 -14
- package/src/types/dataservices.ts +17 -0
- package/src/types/organizations.ts +11 -1
- 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/Datafair.client-E5D6ePRC.js +0 -35
- package/dist/JsonPreview.client-C-6eBbPw.js +0 -87
- package/dist/MapContainer.client-DRkAmdOc.js +0 -105
- package/dist/Pmtiles.client-BR7_ldHY.js +0 -25190
- package/dist/Swagger.client-D4-F6yEf.js +0 -4
- package/dist/XmlPreview.client-Dl2VCgXF.js +0 -79
- package/dist/main-B2kXxWRG.js +0 -105833
- 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
- /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
|
@@ -1,89 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</h3>
|
|
13
|
-
<CopyButton
|
|
14
|
-
:label="t('Copier le lien')"
|
|
15
|
-
:copied-label="t('Lien copié !')"
|
|
16
|
-
:text="resourceExternalUrl"
|
|
17
|
-
/>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="text-gray-medium text-xs flex items-center gap-1">
|
|
20
|
-
<span>{{ t('mis à jour {date}', { date: formatRelativeIfRecentDate(resource.last_modified) }) }}</span>
|
|
21
|
-
<RiSubtractLine
|
|
22
|
-
aria-hidden="true"
|
|
23
|
-
class="size-3 fill-gray-medium"
|
|
24
|
-
/>
|
|
25
|
-
<template v-if="resource.format">
|
|
26
|
-
<span>
|
|
27
|
-
{{ resource.format.trim().toLowerCase() }}
|
|
28
|
-
<span v-if="resourceFilesize">({{ filesize(resourceFilesize) }})</span>
|
|
29
|
-
</span>
|
|
30
|
-
<RiSubtractLine
|
|
31
|
-
aria-hidden="true"
|
|
32
|
-
class="size-3 fill-gray-medium"
|
|
33
|
-
/>
|
|
34
|
-
</template>
|
|
35
|
-
<span class="inline-flex items-center">
|
|
36
|
-
<RiDownloadLine class="size-3 mr-0.5" />
|
|
37
|
-
{{ summarize(resource.metrics.views) }}
|
|
38
|
-
</span>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
<div class="flex items-center gap-2">
|
|
42
|
-
<BrandedButton
|
|
43
|
-
v-if="isResourceUrl"
|
|
44
|
-
:href="resource.latest"
|
|
45
|
-
:title="t('Lien du fichier - ouvre une nouvelle fenêtre')"
|
|
46
|
-
rel="ugc nofollow noopener"
|
|
47
|
-
new-tab
|
|
48
|
-
size="xs"
|
|
49
|
-
external
|
|
50
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
|
|
51
|
-
>
|
|
52
|
-
{{ t('Visiter') }}
|
|
53
|
-
</BrandedButton>
|
|
54
|
-
<BrandedButton
|
|
55
|
-
v-else-if="ogcService"
|
|
56
|
-
:icon="RiFileCopyLine"
|
|
57
|
-
color="primary"
|
|
58
|
-
size="xs"
|
|
59
|
-
@click="copyResourceUrl"
|
|
60
|
-
>
|
|
61
|
-
{{ t('Copier le lien') }}
|
|
62
|
-
</BrandedButton>
|
|
63
|
-
<BrandedButton
|
|
64
|
-
v-else
|
|
65
|
-
:href="resource.latest"
|
|
66
|
-
rel="ugc nofollow noopener"
|
|
67
|
-
:title="downloadButtonTitle"
|
|
68
|
-
download
|
|
69
|
-
class="matomo_download"
|
|
70
|
-
:icon="unavailable ? RiFileWarningLine : RiDownloadLine"
|
|
71
|
-
size="xs"
|
|
72
|
-
color="primary"
|
|
73
|
-
external
|
|
74
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
|
|
75
|
-
>
|
|
76
|
-
{{ t('Télécharger') }}
|
|
77
|
-
</BrandedButton>
|
|
78
|
-
</div>
|
|
79
|
-
</header>
|
|
2
|
+
<div :class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : ''">
|
|
3
|
+
<ResourceViewerHeader
|
|
4
|
+
:dataset
|
|
5
|
+
:resource
|
|
6
|
+
:resources
|
|
7
|
+
:resource-to
|
|
8
|
+
:explore-to="exploreTo"
|
|
9
|
+
:replace
|
|
10
|
+
:fullscreen
|
|
11
|
+
/>
|
|
80
12
|
|
|
81
|
-
<section class="
|
|
13
|
+
<section :class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : ''">
|
|
82
14
|
<TabGroup
|
|
83
15
|
size="sm"
|
|
16
|
+
:default-index="defaultTabIndex"
|
|
17
|
+
:class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : ''"
|
|
84
18
|
@change="switchTab"
|
|
85
19
|
>
|
|
86
|
-
<div class="
|
|
20
|
+
<div class="flex shrink-0 items-center border-b border-gray-default p-2">
|
|
87
21
|
<TabList class="max-w-full overflow-x-auto">
|
|
88
22
|
<Tab
|
|
89
23
|
v-for="tab in tabsOptions"
|
|
@@ -93,13 +27,16 @@
|
|
|
93
27
|
</Tab>
|
|
94
28
|
</TabList>
|
|
95
29
|
</div>
|
|
96
|
-
<TabPanels>
|
|
30
|
+
<TabPanels :class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : ''">
|
|
97
31
|
<TabPanel
|
|
98
32
|
v-for="tab in tabsOptions"
|
|
99
33
|
:key="tab.key"
|
|
100
|
-
class="
|
|
34
|
+
:class="[tab.key === 'data' || tab.key === 'map' ? '' : 'p-4', fullscreen ? 'flex min-h-0 flex-1 flex-col' : '']"
|
|
101
35
|
>
|
|
102
|
-
<div
|
|
36
|
+
<div
|
|
37
|
+
v-if="tab.key === 'map'"
|
|
38
|
+
:class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : 'h-[600px]'"
|
|
39
|
+
>
|
|
103
40
|
<Pmtiles
|
|
104
41
|
v-if="hasPmtiles"
|
|
105
42
|
:resource="resource"
|
|
@@ -109,33 +46,81 @@
|
|
|
109
46
|
v-if="ogcWms"
|
|
110
47
|
:resource="resource"
|
|
111
48
|
/>
|
|
49
|
+
<PreviewUnavailable v-if="!hasPmtiles && !ogcWms && hasPmtilesError">
|
|
50
|
+
{{ t("La carte n'a pas pu être générée automatiquement pour ce fichier.") }}
|
|
51
|
+
<br>
|
|
52
|
+
<span class="text-gray-medium text-xs">{{ pmtilesError }}</span>
|
|
53
|
+
</PreviewUnavailable>
|
|
112
54
|
</div>
|
|
113
|
-
<div
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
55
|
+
<div
|
|
56
|
+
v-if="tab.key === 'data'"
|
|
57
|
+
:class="fullscreen ? 'flex min-h-0 flex-1 flex-col' : ''"
|
|
58
|
+
>
|
|
59
|
+
<!-- Wrapped in Suspense so switching to this tab (or loading its data) shows
|
|
60
|
+
the table skeleton instead of a blank gap while TabularExplorer resolves. -->
|
|
61
|
+
<Suspense
|
|
62
|
+
v-if="previewKind === 'tabular'"
|
|
63
|
+
:timeout="200"
|
|
64
|
+
>
|
|
65
|
+
<TabularExplorer :resource-id="resource.id">
|
|
66
|
+
<TabularToolbar class="shrink-0 border-b border-gray-default p-2" />
|
|
67
|
+
<TabularTable :fill="fullscreen" />
|
|
68
|
+
<TabularMobileFilters />
|
|
69
|
+
</TabularExplorer>
|
|
70
|
+
<template #fallback>
|
|
71
|
+
<TabularSkeleton :fill="fullscreen" />
|
|
72
|
+
</template>
|
|
73
|
+
</Suspense>
|
|
74
|
+
|
|
75
|
+
<!-- PDF is a full-bleed visual preview like the table and the map: it
|
|
76
|
+
owns its own reader backdrop, so it sits outside the padded wrapper. -->
|
|
118
77
|
<PdfPreview
|
|
119
|
-
v-else-if="
|
|
78
|
+
v-else-if="previewKind === 'pdf'"
|
|
120
79
|
:resource="resource"
|
|
80
|
+
:fill="fullscreen"
|
|
121
81
|
/>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/>
|
|
126
|
-
<DatafairPreview
|
|
127
|
-
v-else-if="hasDatafairPreview"
|
|
128
|
-
:resource="resource"
|
|
129
|
-
:dataset="dataset"
|
|
130
|
-
/>
|
|
131
|
-
<SwaggerClient
|
|
132
|
-
v-else-if="hasOpenAPIPreview"
|
|
133
|
-
:url="resource.extras['apidocUrl'] as string"
|
|
134
|
-
/>
|
|
135
|
-
<Preview
|
|
82
|
+
|
|
83
|
+
<!-- Text previews stay padded inside the tab panel -->
|
|
84
|
+
<div
|
|
136
85
|
v-else
|
|
137
|
-
|
|
138
|
-
|
|
86
|
+
class="p-4"
|
|
87
|
+
>
|
|
88
|
+
<JsonPreview
|
|
89
|
+
v-if="previewKind === 'json'"
|
|
90
|
+
:resource="resource"
|
|
91
|
+
/>
|
|
92
|
+
<XmlPreview
|
|
93
|
+
v-else-if="previewKind === 'xml'"
|
|
94
|
+
:resource="resource"
|
|
95
|
+
/>
|
|
96
|
+
<ImagePreview
|
|
97
|
+
v-else-if="previewKind === 'image'"
|
|
98
|
+
:resource="resource"
|
|
99
|
+
/>
|
|
100
|
+
<DatafairPreview
|
|
101
|
+
v-else-if="previewKind === 'datafair'"
|
|
102
|
+
:resource="resource"
|
|
103
|
+
:dataset="dataset"
|
|
104
|
+
/>
|
|
105
|
+
<OpenApiViewer
|
|
106
|
+
v-else-if="previewKind === 'openapi'"
|
|
107
|
+
:url="resource.extras['apidocUrl'] as string"
|
|
108
|
+
/>
|
|
109
|
+
<PreviewUnavailable v-else>
|
|
110
|
+
<!-- "File too large to download" is the only analysis:error value from hydra for now -->
|
|
111
|
+
<template v-if="resource.extras['analysis:error'] === 'File too large to download'">
|
|
112
|
+
{{ t("Ce fichier est trop volumineux pour être analysé et prévisualisé. Téléchargez-le avec le bouton Télécharger.") }}
|
|
113
|
+
</template>
|
|
114
|
+
<template v-else-if="resource.extras['analysis:parsing:error']">
|
|
115
|
+
{{ t("L'analyse de ce fichier a rencontré une erreur, l'aperçu n'est pas disponible. Téléchargez-le avec le bouton Télécharger.") }}
|
|
116
|
+
<br>
|
|
117
|
+
<span class="text-gray-medium text-xs">{{ resource.extras['analysis:parsing:error'] }}</span>
|
|
118
|
+
</template>
|
|
119
|
+
<template v-else>
|
|
120
|
+
{{ t("Ce fichier ne peut pas être prévisualisé. Téléchargez-le avec le bouton Télécharger.") }}
|
|
121
|
+
</template>
|
|
122
|
+
</PreviewUnavailable>
|
|
123
|
+
</div>
|
|
139
124
|
</div>
|
|
140
125
|
<div v-if="tab.key === 'description'">
|
|
141
126
|
<MarkdownViewer
|
|
@@ -152,138 +137,17 @@
|
|
|
152
137
|
<div v-if="tab.key === 'metadata'">
|
|
153
138
|
<Metadata :resource />
|
|
154
139
|
</div>
|
|
155
|
-
<div v-if="tab.key === '
|
|
156
|
-
<dl class="fr-pl-0">
|
|
157
|
-
<dt
|
|
158
|
-
v-if="resource.format === 'url'"
|
|
159
|
-
class="font-bold fr-text--sm fr-mb-0"
|
|
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>
|
|
278
|
-
</div>
|
|
279
|
-
<div v-if="tab.key === 'swagger'">
|
|
140
|
+
<div v-if="tab.key === 'api'">
|
|
280
141
|
<div class="fr-mb-4w">
|
|
281
142
|
<p>{{ t("Cette API est générée automatiquement par {platform} à partir du fichier.", { platform: config.name }) }}</p>
|
|
282
143
|
<p>{{ t("- Si le fichier est modifié, l'API sera mise à jour et sa structure pourra changer.") }}</p>
|
|
283
144
|
<p>{{ t("- Si le fichier est supprimé, l'API sera également supprimée.") }}</p>
|
|
284
145
|
<p>{{ t("Pour des usages pérennes, prévoyez que cette API dépend directement du fichier source.") }}</p>
|
|
146
|
+
<p v-if="config.tabularApiUrl">
|
|
147
|
+
{{ t("L'URL de base de l'API est {url}", { url: config.tabularApiUrl }) }}
|
|
148
|
+
</p>
|
|
285
149
|
</div>
|
|
286
|
-
<
|
|
150
|
+
<OpenApiViewer
|
|
287
151
|
v-if="hasTabularData"
|
|
288
152
|
:url="`${config.tabularApiUrl}/api/resources/${resource.id}/swagger/`"
|
|
289
153
|
/>
|
|
@@ -297,30 +161,29 @@
|
|
|
297
161
|
|
|
298
162
|
<script setup lang="ts">
|
|
299
163
|
import { computed, defineAsyncComponent } from 'vue'
|
|
300
|
-
import {
|
|
301
|
-
import
|
|
302
|
-
import BrandedButton from '../BrandedButton.vue'
|
|
303
|
-
import CopyButton from '../CopyButton.vue'
|
|
164
|
+
import { useRoute, useRouter } from 'vue-router'
|
|
165
|
+
import PreviewUnavailable from '../ResourceAccordion/PreviewUnavailable.vue'
|
|
304
166
|
import MarkdownViewer from '../MarkdownViewer.vue'
|
|
305
|
-
import
|
|
306
|
-
import Swagger from '../ResourceAccordion/Swagger.client.vue'
|
|
167
|
+
import OpenApiViewer from '../OpenApiViewer/OpenApiViewer.vue'
|
|
307
168
|
import TabGroup from '../Tabs/TabGroup.vue'
|
|
308
169
|
import TabList from '../Tabs/TabList.vue'
|
|
309
170
|
import Tab from '../Tabs/Tab.vue'
|
|
310
171
|
import TabPanels from '../Tabs/TabPanels.vue'
|
|
311
172
|
import TabPanel from '../Tabs/TabPanel.vue'
|
|
312
|
-
import
|
|
313
|
-
import
|
|
173
|
+
import TabularExplorer from '../TabularExplorer/TabularExplorer.vue'
|
|
174
|
+
import TabularToolbar from '../TabularExplorer/TabularToolbar.vue'
|
|
175
|
+
import TabularTable from '../TabularExplorer/TabularTable.vue'
|
|
176
|
+
import TabularMobileFilters from '../TabularExplorer/TabularMobileFilters.vue'
|
|
177
|
+
import TabularSkeleton from '../TabularExplorer/TabularSkeleton.vue'
|
|
314
178
|
import DataStructure from '../ResourceAccordion/DataStructure.vue'
|
|
315
179
|
import Metadata from '../ResourceAccordion/Metadata.vue'
|
|
316
|
-
import
|
|
317
|
-
import { getResourceFormatIcon } from '../../functions/resources'
|
|
318
|
-
import { getResourceExternalUrl, getResourceFilesize } from '../../functions/datasets'
|
|
180
|
+
import ResourceViewerHeader from './ResourceViewerHeader.vue'
|
|
319
181
|
import { trackEvent } from '../../functions/matomo'
|
|
320
182
|
import { useComponentsConfig } from '../../config'
|
|
321
|
-
import { useFormatDate } from '../../functions/dates'
|
|
322
183
|
import { useTranslation } from '../../composables/useTranslation'
|
|
323
184
|
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
|
|
185
|
+
import { provideTabularProfile } from '../../composables/useTabularProfile'
|
|
186
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
324
187
|
import type { Resource } from '../../types/resources'
|
|
325
188
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
326
189
|
|
|
@@ -333,6 +196,9 @@ const PdfPreview = defineAsyncComponent(() =>
|
|
|
333
196
|
const XmlPreview = defineAsyncComponent(() =>
|
|
334
197
|
import('../ResourceAccordion/XmlPreview.client.vue'),
|
|
335
198
|
)
|
|
199
|
+
const ImagePreview = defineAsyncComponent(() =>
|
|
200
|
+
import('../ResourceAccordion/ImagePreview.client.vue'),
|
|
201
|
+
)
|
|
336
202
|
const DatafairPreview = defineAsyncComponent(() =>
|
|
337
203
|
import('../ResourceAccordion/Datafair.client.vue'),
|
|
338
204
|
)
|
|
@@ -342,63 +208,60 @@ const MapContainer = defineAsyncComponent(() =>
|
|
|
342
208
|
const Pmtiles = defineAsyncComponent(() =>
|
|
343
209
|
import('../ResourceAccordion/Pmtiles.client.vue'),
|
|
344
210
|
)
|
|
345
|
-
const SwaggerClient = defineAsyncComponent(() =>
|
|
346
|
-
import('../ResourceAccordion/Swagger.client.vue'),
|
|
347
|
-
)
|
|
348
211
|
|
|
349
|
-
const props = defineProps<{
|
|
212
|
+
const props = withDefaults(defineProps<{
|
|
350
213
|
dataset: Dataset | DatasetV2
|
|
351
214
|
resource: Resource
|
|
352
|
-
|
|
215
|
+
resources?: Resource[]
|
|
216
|
+
resourceTo: (resource: Resource) => RouteLocationRaw
|
|
217
|
+
// When provided (inline mode), shows an "Explorer" button next to the download
|
|
218
|
+
// action that opens the fullscreen explorer on the current resource.
|
|
219
|
+
exploreTo?: (resource: Resource) => string
|
|
220
|
+
replace?: boolean
|
|
221
|
+
// Fullscreen mode: make the viewer a flex column so the table fills down to the
|
|
222
|
+
// bottom, and hide the inline download/visit/copy actions — they're shown in the
|
|
223
|
+
// dataset context bar above. Inline mode (dataset page) shows them in the header.
|
|
224
|
+
fullscreen?: boolean
|
|
225
|
+
}>(), {
|
|
226
|
+
fullscreen: false,
|
|
227
|
+
})
|
|
353
228
|
|
|
354
229
|
const { t } = useTranslation()
|
|
355
230
|
const config = useComponentsConfig()
|
|
356
|
-
const
|
|
231
|
+
const route = useRoute()
|
|
232
|
+
const router = useRouter()
|
|
357
233
|
|
|
358
234
|
const {
|
|
235
|
+
previewKind,
|
|
359
236
|
hasTabularData,
|
|
360
237
|
hasPmtiles,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
ogcService,
|
|
238
|
+
hasPmtilesError,
|
|
239
|
+
pmtilesError,
|
|
364
240
|
ogcWms,
|
|
365
|
-
generatedFormats,
|
|
366
|
-
wfsFormats,
|
|
367
|
-
defaultWfsProjection,
|
|
368
|
-
isResourceUrl,
|
|
369
241
|
tabsOptions,
|
|
370
242
|
} = useResourceCapabilities(() => props.resource, () => props.dataset)
|
|
371
243
|
|
|
372
|
-
|
|
373
|
-
|
|
244
|
+
// Share the tabular profile fetch between TabularExplorer and DataStructure tabs.
|
|
245
|
+
// Only tabular resources have one: asking for the profile of a PDF or an image is a
|
|
246
|
+
// request to the Tabular API that can only fail.
|
|
247
|
+
if (hasTabularData.value) {
|
|
248
|
+
await provideTabularProfile(() => props.resource.id)
|
|
249
|
+
}
|
|
374
250
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
return t('Télécharger le fichier en {format}', { format: format.value })
|
|
251
|
+
// The active tab lives in the URL so a shared link opens on the same one. Read once
|
|
252
|
+
// at mount (TabGroup only takes an initial index), which is enough: switching resource
|
|
253
|
+
// remounts the viewer, and the tab is preserved when the new resource also has it.
|
|
254
|
+
const defaultTabIndex = computed(() => {
|
|
255
|
+
const index = tabsOptions.value.findIndex(option => option.key === route.query.tab)
|
|
256
|
+
return index === -1 ? 0 : index
|
|
383
257
|
})
|
|
384
258
|
|
|
385
|
-
const conversionsLastUpdate = computed(() =>
|
|
386
|
-
formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined),
|
|
387
|
-
)
|
|
388
|
-
|
|
389
|
-
const copyResourceUrl = async () => {
|
|
390
|
-
try {
|
|
391
|
-
await navigator.clipboard.writeText(props.resource.url)
|
|
392
|
-
toast.success(t('Lien copié !'))
|
|
393
|
-
}
|
|
394
|
-
catch {
|
|
395
|
-
toast.error(t('Impossible de copier dans le presse-papier'))
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
259
|
const switchTab = (index: number) => {
|
|
400
260
|
const option = tabsOptions.value[index]
|
|
401
261
|
if (!option) return
|
|
262
|
+
// The first tab is the default: drop `tab` rather than writing it in the URL.
|
|
263
|
+
const { tab: _, ...query } = route.query
|
|
264
|
+
router.replace({ query: index === 0 ? query : { ...query, tab: option.key } })
|
|
402
265
|
trackEvent('View resource tab', props.resource.id, option.label)
|
|
403
266
|
if (option.key === 'data') {
|
|
404
267
|
trackEvent('Show preview', props.resource.id)
|