@datagouv/components-next 1.0.2-dev.93 → 1.0.2-dev.94
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-CQNz2GL7.js → Datafair.client-8bXp6UeQ.js} +1 -1
- package/dist/{JsonPreview.client-DQh095Dl.js → JsonPreview.client-BxuoPK_w.js} +2 -2
- package/dist/{MapContainer.client-CszeqIWr.js → MapContainer.client-CTz0wmJG.js} +2 -2
- package/dist/{PdfPreview.client-DKpKZprd.js → PdfPreview.client-DpVreUSl.js} +2 -2
- package/dist/{Pmtiles.client-BnPqJIsF.js → Pmtiles.client-BwmHo3T8.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-7Q6USQh2.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-stmU5qEB.js} +1 -1
- package/dist/{XmlPreview.client-C75QZMsm.js → XmlPreview.client-DAOs89cR.js} +3 -3
- package/dist/components-next.js +1 -1
- package/dist/{index-DfFbOdzV.js → index-JqjPja1u.js} +1 -1
- package/dist/{main-DEpfIocP.js → main-D4WQMky0.js} +370 -371
- package/dist/{vue3-xml-viewer.common-ByPlyYhy.js → vue3-xml-viewer.common-BGsoNyZe.js} +1 -1
- package/package.json +1 -1
- package/src/composables/useMetrics.ts +1 -1
- package/src/config.ts +17 -3
- package/src/functions/api.ts +5 -34
- package/src/functions/metrics.ts +6 -4
- package/src/main.ts +27 -0
package/package.json
CHANGED
|
@@ -13,6 +13,6 @@ export function useMetrics() {
|
|
|
13
13
|
getDatasetMetrics: (datasetId: string) => getDatasetMetrics(datasetId, config.metricsApiUrl!),
|
|
14
14
|
getDataserviceMetrics: (dataserviceId: string) => getDataserviceMetrics(dataserviceId, config.metricsApiUrl!),
|
|
15
15
|
getReuseMetrics: (reuseId: string) => getReuseMetrics(reuseId, config.metricsApiUrl!),
|
|
16
|
-
createDatasetsForOrganizationMetricsUrl: (organizationId: string) => createDatasetsForOrganizationMetricsUrl(organizationId, config.metricsApiUrl!, config.apiBase),
|
|
16
|
+
createDatasetsForOrganizationMetricsUrl: (organizationId: string) => createDatasetsForOrganizationMetricsUrl(organizationId, config.metricsApiUrl!, config.apiBase, config.$fetch),
|
|
17
17
|
}
|
|
18
18
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inject, type Component, type InjectionKey } from 'vue'
|
|
2
2
|
import type { UseFetchFunction } from './functions/api.types'
|
|
3
|
-
import type { FetchOptions } from 'ofetch'
|
|
3
|
+
import type { $Fetch, FetchOptions } from 'ofetch'
|
|
4
4
|
|
|
5
5
|
export type PluginConfig = {
|
|
6
6
|
name: string // Name of the application (ex: data.gouv.fr)
|
|
@@ -25,6 +25,16 @@ export type PluginConfig = {
|
|
|
25
25
|
tabularAllowRemote?: boolean
|
|
26
26
|
tabularApiDataserviceId?: string
|
|
27
27
|
customUseFetch?: UseFetchFunction | null
|
|
28
|
+
/**
|
|
29
|
+
* Imperative configured fetch (auth, headers, error handling): the single source of truth for
|
|
30
|
+
* requests. The default `useFetch` uses it as its transport, and imperative helpers (metrics CSV
|
|
31
|
+
* export, …) call it directly — so they never need a `?? ofetch` fallback.
|
|
32
|
+
* Optional for consumers: when omitted, the plugin defaults it to an `ofetch` instance built from
|
|
33
|
+
* the `onRequest`/`onResponse` hooks below (see the `datagouv` plugin install). A consumer can
|
|
34
|
+
* instead provide its own (e.g. a Bearer-authenticated `$fetch`) and skip the hooks entirely.
|
|
35
|
+
*/
|
|
36
|
+
$fetch?: $Fetch | null
|
|
37
|
+
/** Auth/headers/error hooks. Folded into the default `$fetch` when no `$fetch` is provided. */
|
|
28
38
|
onRequest?: FetchOptions['onRequest']
|
|
29
39
|
onRequestError?: FetchOptions['onRequestError']
|
|
30
40
|
onResponse?: FetchOptions['onResponse']
|
|
@@ -38,8 +48,12 @@ export type PluginConfig = {
|
|
|
38
48
|
|
|
39
49
|
export const configKey = Symbol() as InjectionKey<PluginConfig>
|
|
40
50
|
|
|
41
|
-
|
|
51
|
+
// After the `datagouv` plugin install, `$fetch` is always set (defaulted to an ofetch instance), so
|
|
52
|
+
// consumers of the config can rely on it without a fallback.
|
|
53
|
+
export type ResolvedPluginConfig = PluginConfig & { $fetch: $Fetch }
|
|
54
|
+
|
|
55
|
+
export function useComponentsConfig(): ResolvedPluginConfig {
|
|
42
56
|
const config = inject(configKey)
|
|
43
57
|
if (!config) throw new Error('Calling `useComponentsConfig` outside @datagouv/components')
|
|
44
|
-
return config
|
|
58
|
+
return config as ResolvedPluginConfig
|
|
45
59
|
}
|
package/src/functions/api.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
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
|
-
import { useTranslation } from '../composables/useTranslation'
|
|
5
4
|
import type { AsyncData, AsyncDataRequestStatus, UseFetchOptions } from './api.types'
|
|
6
5
|
|
|
7
6
|
function deepToValue(obj: MaybeRefOrGetter<Record<string, unknown> | undefined>): Record<string, unknown> | undefined {
|
|
@@ -18,8 +17,6 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
18
17
|
): Promise<AsyncData<DataT, ErrorT>> {
|
|
19
18
|
const config = useComponentsConfig()
|
|
20
19
|
|
|
21
|
-
const { locale } = useTranslation()
|
|
22
|
-
|
|
23
20
|
if (config.customUseFetch) {
|
|
24
21
|
return await config.customUseFetch(url, options)
|
|
25
22
|
}
|
|
@@ -37,38 +34,12 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
37
34
|
status.value = 'pending'
|
|
38
35
|
try {
|
|
39
36
|
data.value = isRaw
|
|
37
|
+
// Raw targets another data.gouv service (the Tabular API in TabularExplorer) via its own
|
|
38
|
+
// absolute URL, so it must stay bare ofetch: no datagouv apiBase, no datagouv auth attached.
|
|
40
39
|
? await ofetch<DataT | null>(urlValue, { params: params ?? query })
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
onRequest(param) {
|
|
45
|
-
if (config.onRequest) {
|
|
46
|
-
if (Array.isArray(config.onRequest)) {
|
|
47
|
-
config.onRequest.forEach(r => r(param))
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
config.onRequest(param)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const { options } = param
|
|
54
|
-
options.headers.set('Content-Type', 'application/json')
|
|
55
|
-
options.headers.set('Accept', 'application/json')
|
|
56
|
-
options.credentials = 'include'
|
|
57
|
-
if (config.devApiKey) {
|
|
58
|
-
options.headers.set('X-API-KEY', config.devApiKey)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (locale) {
|
|
62
|
-
if (!options.params) {
|
|
63
|
-
options.params = {}
|
|
64
|
-
}
|
|
65
|
-
options.params['lang'] = locale
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
onRequestError: config.onRequestError,
|
|
69
|
-
onResponse: config.onResponse,
|
|
70
|
-
onResponseError: config.onResponseError,
|
|
71
|
-
})
|
|
40
|
+
// The configured `$fetch` carries baseURL + auth + headers (see the `datagouv` plugin install
|
|
41
|
+
// for the default one). We only forward the URL and params here.
|
|
42
|
+
: await config.$fetch<DataT | null>(urlValue, { baseURL: config.apiBase, params: params ?? query })
|
|
72
43
|
status.value = 'success'
|
|
73
44
|
}
|
|
74
45
|
catch (e) {
|
package/src/functions/metrics.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { escapeCsvValue } from './helpers'
|
|
2
|
-
import { ofetch } from 'ofetch'
|
|
2
|
+
import { ofetch, type $Fetch } from 'ofetch'
|
|
3
3
|
import type { DatasetV2 } from '../types/datasets'
|
|
4
4
|
import type { PaginatedArray } from '../types/api'
|
|
5
5
|
|
|
@@ -119,14 +119,16 @@ export async function getDatasetMetrics(datasetId: string, metricsApi: string):
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export async function createDatasetsForOrganizationMetricsUrl(organizationId: string, metricsApi: string, apiBase: string) {
|
|
122
|
+
export async function createDatasetsForOrganizationMetricsUrl(organizationId: string, metricsApi: string, apiBase: string, apiFetch: $Fetch) {
|
|
123
123
|
let data = 'dataset_title,dataset_id,month,monthly_visit,monthly_download_resource\n'
|
|
124
124
|
|
|
125
|
-
// fetch datasets info from organization datasets
|
|
125
|
+
// fetch datasets info from organization datasets through the configured fetch, so it carries the
|
|
126
|
+
// consumer's auth (cookie for cdata via `$api`, Bearer for verticals) instead of a hardcoded
|
|
127
|
+
// `credentials: 'include'`, which breaks CORS cross-origin on the verticals.
|
|
126
128
|
const datasets: Record<string, Record<string, string>> = {}
|
|
127
129
|
let datasetsUrl: string | null = `/api/2/datasets/?organization=${organizationId}&page_size=200`
|
|
128
130
|
while (datasetsUrl) {
|
|
129
|
-
const body: PaginatedArray<DatasetV2> = await
|
|
131
|
+
const body: PaginatedArray<DatasetV2> = await apiFetch(datasetsUrl, { baseURL: apiBase })
|
|
130
132
|
datasetsUrl = body.next_page
|
|
131
133
|
for (const row of body.data) {
|
|
132
134
|
datasets[row.id] = { title: row.title }
|
package/src/main.ts
CHANGED
|
@@ -104,6 +104,8 @@ import InfiniteLoader from './components/InfiniteLoader.vue'
|
|
|
104
104
|
import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
|
|
105
105
|
import type { UseFetchFunction } from './functions/api.types'
|
|
106
106
|
import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
|
|
107
|
+
import { ofetch } from 'ofetch'
|
|
108
|
+
import { useTranslation } from './composables/useTranslation'
|
|
107
109
|
|
|
108
110
|
export { Toaster, toast } from 'vue-sonner'
|
|
109
111
|
|
|
@@ -278,6 +280,31 @@ export {
|
|
|
278
280
|
// Vue Plugin
|
|
279
281
|
const datagouv: Plugin<PluginConfig> = {
|
|
280
282
|
async install(app: App, options) {
|
|
283
|
+
// Default `$fetch` to an ofetch instance carrying the datagouv API specifics + the consumer's
|
|
284
|
+
// auth hooks, so everything downstream (the default `useFetch`, imperative helpers) can rely on
|
|
285
|
+
// a single configured fetch. A consumer that provides its own `$fetch` keeps full control.
|
|
286
|
+
if (!options.$fetch) {
|
|
287
|
+
options.$fetch = ofetch.create({
|
|
288
|
+
baseURL: options.apiBase,
|
|
289
|
+
onRequest(context) {
|
|
290
|
+
if (options.onRequest) {
|
|
291
|
+
if (Array.isArray(options.onRequest)) options.onRequest.forEach(hook => hook(context))
|
|
292
|
+
else options.onRequest(context)
|
|
293
|
+
}
|
|
294
|
+
context.options.headers.set('Content-Type', 'application/json')
|
|
295
|
+
context.options.headers.set('Accept', 'application/json')
|
|
296
|
+
if (options.devApiKey) context.options.headers.set('X-API-KEY', options.devApiKey)
|
|
297
|
+
const { locale } = useTranslation()
|
|
298
|
+
if (locale) {
|
|
299
|
+
context.options.params ??= {}
|
|
300
|
+
context.options.params['lang'] = locale
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
onRequestError: options.onRequestError,
|
|
304
|
+
onResponse: options.onResponse,
|
|
305
|
+
onResponseError: options.onResponseError,
|
|
306
|
+
})
|
|
307
|
+
}
|
|
281
308
|
app.provide(configKey, options)
|
|
282
309
|
if (!options.textClamp) {
|
|
283
310
|
const textClamp = await import('vue3-text-clamp')
|