@datagouv/components-next 1.0.2-dev.0 → 1.0.2-dev.2
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/dist/{Datafair.client-DpeBuzZZ.js → Datafair.client-E5D6ePRC.js} +1 -1
- package/dist/{JsonPreview.client-B3sQR-rW.js → JsonPreview.client-C-6eBbPw.js} +1 -1
- package/dist/{MapContainer.client-BA6GCqKX.js → MapContainer.client-DRkAmdOc.js} +2 -2
- package/dist/{PdfPreview.client-CbeSChb8.js → PdfPreview.client-C-w6-w44.js} +1 -1
- package/dist/{Pmtiles.client-D8pFim1L.js → Pmtiles.client-BR7_ldHY.js} +1 -1
- package/dist/Swagger.client-D4-F6yEf.js +4 -0
- package/dist/{XmlPreview.client-DWJt61wG.js → XmlPreview.client-Dl2VCgXF.js} +2 -2
- package/dist/components-next.js +1 -1
- package/dist/{index-DVp7Y0Xu.js → index-SrYZwgCT.js} +1 -1
- package/dist/{main-CrSRA2X-.js → main-B2kXxWRG.js} +19056 -18953
- package/dist/{vue3-xml-viewer.common-BjA4LdSC.js → vue3-xml-viewer.common-BRxsqI9j.js} +1 -1
- package/package.json +1 -1
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +50 -1
- package/src/composables/useResourceCapabilities.ts +15 -1
- package/src/functions/api.ts +11 -3
- package/src/functions/resourceCapabilities.ts +55 -0
- package/src/types/resources.ts +10 -0
- package/dist/Swagger.client-B-2Q16qa.js +0 -4
package/package.json
CHANGED
|
@@ -228,6 +228,52 @@
|
|
|
228
228
|
/>
|
|
229
229
|
</dd>
|
|
230
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>
|
|
231
277
|
</dl>
|
|
232
278
|
</div>
|
|
233
279
|
<div v-if="tab.key === 'swagger'">
|
|
@@ -251,7 +297,7 @@
|
|
|
251
297
|
|
|
252
298
|
<script setup lang="ts">
|
|
253
299
|
import { computed, defineAsyncComponent } from 'vue'
|
|
254
|
-
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
|
|
300
|
+
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiInformationLine, RiSubtractLine } from '@remixicon/vue'
|
|
255
301
|
import { toast } from 'vue-sonner'
|
|
256
302
|
import BrandedButton from '../BrandedButton.vue'
|
|
257
303
|
import CopyButton from '../CopyButton.vue'
|
|
@@ -263,6 +309,7 @@ import TabList from '../Tabs/TabList.vue'
|
|
|
263
309
|
import Tab from '../Tabs/Tab.vue'
|
|
264
310
|
import TabPanels from '../Tabs/TabPanels.vue'
|
|
265
311
|
import TabPanel from '../Tabs/TabPanel.vue'
|
|
312
|
+
import Tooltip from '../Tooltip.vue'
|
|
266
313
|
import Preview from '../ResourceAccordion/Preview.vue'
|
|
267
314
|
import DataStructure from '../ResourceAccordion/DataStructure.vue'
|
|
268
315
|
import Metadata from '../ResourceAccordion/Metadata.vue'
|
|
@@ -316,6 +363,8 @@ const {
|
|
|
316
363
|
ogcService,
|
|
317
364
|
ogcWms,
|
|
318
365
|
generatedFormats,
|
|
366
|
+
wfsFormats,
|
|
367
|
+
defaultWfsProjection,
|
|
319
368
|
isResourceUrl,
|
|
320
369
|
tabsOptions,
|
|
321
370
|
} = useResourceCapabilities(() => props.resource, () => props.dataset)
|
|
@@ -4,8 +4,9 @@ import { useTranslation } from './useTranslation'
|
|
|
4
4
|
import { useHasTabularData } from './useHasTabularData'
|
|
5
5
|
import { detectOgcService } from '../functions/resources'
|
|
6
6
|
import { isOrganizationCertified } from '../functions/organizations'
|
|
7
|
-
import type { Resource } from '../types/resources'
|
|
7
|
+
import type { Resource, WfsMetadata } from '../types/resources'
|
|
8
8
|
import type { Dataset, DatasetV2 } from '../types/datasets'
|
|
9
|
+
import { getWfsExportFormats } from '../functions/resourceCapabilities'
|
|
9
10
|
|
|
10
11
|
const GENERATED_FORMATS = ['parquet', 'pmtiles', 'geojson']
|
|
11
12
|
const URL_FORMATS = ['url', 'doi', 'www:link', 'www:link-1.0-http--link', 'www:link-1.0-http--partners', 'www:link-1.0-http--related', 'www:link-1.0-http--samples']
|
|
@@ -67,6 +68,17 @@ export function useResourceCapabilities(
|
|
|
67
68
|
return formats
|
|
68
69
|
})
|
|
69
70
|
|
|
71
|
+
const wfsFormats = computed(() => {
|
|
72
|
+
return getWfsExportFormats(toValue(resource))
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const defaultWfsProjection = computed<string | null>(() => {
|
|
76
|
+
const r = toValue(resource)
|
|
77
|
+
const wfsMetadata = r.extras['analysis:parsing:ogc_metadata'] as WfsMetadata | null
|
|
78
|
+
if (!wfsMetadata || wfsMetadata.format !== `wfs`) return null
|
|
79
|
+
return wfsMetadata?.detected_layer?.default_crs ?? null
|
|
80
|
+
})
|
|
81
|
+
|
|
70
82
|
const isResourceUrl = computed(() => URL_FORMATS.includes(toValue(resource).format))
|
|
71
83
|
|
|
72
84
|
const tabsOptions = computed(() => {
|
|
@@ -111,6 +123,8 @@ export function useResourceCapabilities(
|
|
|
111
123
|
ogcService,
|
|
112
124
|
ogcWms,
|
|
113
125
|
generatedFormats,
|
|
126
|
+
wfsFormats,
|
|
127
|
+
defaultWfsProjection,
|
|
114
128
|
isResourceUrl,
|
|
115
129
|
tabsOptions,
|
|
116
130
|
}
|
package/src/functions/api.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import { ref, toValue, watchEffect, onMounted, type ComputedRef, type Ref } from 'vue'
|
|
1
|
+
import { ref, toValue, watchEffect, onMounted, type ComputedRef, type MaybeRefOrGetter, type Ref } from 'vue'
|
|
2
2
|
import { ofetch } from 'ofetch'
|
|
3
3
|
import { useComponentsConfig } from '../config'
|
|
4
4
|
import { useTranslation } from '../composables/useTranslation'
|
|
5
5
|
import type { AsyncData, AsyncDataRequestStatus, UseFetchOptions } from './api.types'
|
|
6
6
|
|
|
7
|
+
function deepToValue(obj: MaybeRefOrGetter<Record<string, unknown> | undefined>): Record<string, unknown> | undefined {
|
|
8
|
+
const val = toValue(obj)
|
|
9
|
+
if (!val || typeof val !== 'object') return val
|
|
10
|
+
return Object.fromEntries(
|
|
11
|
+
Object.entries(val).map(([k, v]) => [k, toValue(v as MaybeRefOrGetter<unknown>)]),
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
export async function useFetch<DataT, ErrorT = never>(
|
|
8
16
|
url: string | Request | Ref<string | Request> | ComputedRef<string | null> | (() => string | Request),
|
|
9
17
|
options?: UseFetchOptions<DataT>,
|
|
@@ -23,8 +31,8 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
23
31
|
const execute = async () => {
|
|
24
32
|
const urlValue = toValue(url)
|
|
25
33
|
if (!urlValue) return
|
|
26
|
-
const params =
|
|
27
|
-
const query =
|
|
34
|
+
const params = deepToValue(options?.params)
|
|
35
|
+
const query = deepToValue(options?.query)
|
|
28
36
|
status.value = 'pending'
|
|
29
37
|
try {
|
|
30
38
|
data.value = await ofetch<DataT | null>(urlValue, {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Resource, WfsMetadata, OgcLayerInfo } from '../types/resources'
|
|
2
|
+
|
|
3
|
+
const WFS_EXPORT_FORMATS = [
|
|
4
|
+
{
|
|
5
|
+
name: 'csv',
|
|
6
|
+
mimetype: 'csv',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'json',
|
|
10
|
+
mimetype: 'application/json',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: 'shp',
|
|
14
|
+
mimetype: 'SHAPE-ZIP',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'gml',
|
|
18
|
+
mimetype: 'application/gml+xml',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'kml',
|
|
22
|
+
mimetype: 'KML',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'gpkg',
|
|
26
|
+
mimetype: 'application/geopackage+sqlite3',
|
|
27
|
+
},
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
function buildWfsDownloadUrl(baseUrl: string, wfsMetadata: WfsMetadata, format: { name: string, mimetype: string }, layer: OgcLayerInfo) {
|
|
31
|
+
const version = wfsMetadata.version
|
|
32
|
+
const query = new URLSearchParams({
|
|
33
|
+
SERVICE: 'WFS',
|
|
34
|
+
REQUEST: 'GetFeature',
|
|
35
|
+
VERSION: version,
|
|
36
|
+
...(Number(version.split('.')[0]) >= 2 ? { TYPENAMES: layer.name } : { TYPENAME: layer.name }),
|
|
37
|
+
OUTPUTFORMAT: format.mimetype,
|
|
38
|
+
...(layer.default_crs ? { SRSNAME: layer.default_crs } : {}),
|
|
39
|
+
})
|
|
40
|
+
return `${baseUrl.split('?')[0]}?${query.toString()}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getWfsExportFormats(resource: Pick<Resource, 'extras' | 'url'>) {
|
|
44
|
+
const wfsMetadata = resource.extras['analysis:parsing:ogc_metadata'] as WfsMetadata | null
|
|
45
|
+
if (!wfsMetadata || wfsMetadata.format !== `wfs`) return []
|
|
46
|
+
const outputFormats = wfsMetadata.output_formats.map((format: string) => format.toLowerCase())
|
|
47
|
+
const layer = wfsMetadata.detected_layer
|
|
48
|
+
if (!layer) return []
|
|
49
|
+
const formats = WFS_EXPORT_FORMATS.filter(format => outputFormats.includes(format.mimetype.toLowerCase()))
|
|
50
|
+
.map(format => ({
|
|
51
|
+
url: buildWfsDownloadUrl(resource.url, wfsMetadata, format, layer),
|
|
52
|
+
format: format.name,
|
|
53
|
+
}))
|
|
54
|
+
return formats
|
|
55
|
+
}
|
package/src/types/resources.ts
CHANGED
|
@@ -41,3 +41,13 @@ export interface ResourceGroup {
|
|
|
41
41
|
total: number
|
|
42
42
|
items: Resource[]
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
export type OgcLayerInfo = { name: string, default_crs: string | null }
|
|
46
|
+
|
|
47
|
+
export type WfsMetadata = {
|
|
48
|
+
format: string
|
|
49
|
+
layers: Array<OgcLayerInfo>
|
|
50
|
+
version: string
|
|
51
|
+
detected_layer: OgcLayerInfo | null
|
|
52
|
+
output_formats: Array<string>
|
|
53
|
+
}
|