@datagouv/components-next 0.0.18 → 0.0.20
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/{JsonPreview.client-DvhnzVAV.js → JsonPreview.client-SDR6QQ7R.js} +33 -32
- package/dist/{MapContainer.client-BTa4cY2w.js → MapContainer.client-grQTB4fm.js} +5 -3
- package/dist/{PdfPreview.client-CFMYzFUs.js → PdfPreview.client-BD1xfGym.js} +32 -31
- package/dist/Pmtiles.client-B3aT7Aun.js +22696 -0
- package/dist/Swagger.client-fEwFVkkQ.js +4 -0
- package/dist/{XmlPreview.client-0NtLStzb.js → XmlPreview.client-CjNckhEP.js} +27 -26
- package/dist/components-next.css +4 -4
- package/dist/components-next.js +33 -32
- package/dist/main-CgjLq1oz.js +100647 -0
- package/dist/{pdf-vue3-D5SzycIl.js → pdf-vue3-Dm2ZCc3P.js} +1 -1
- package/dist/{text-clamp.esm-D43nX9La.js → text-clamp.esm-Mb7Qdtu9.js} +5 -5
- package/dist/{vue3-json-viewer-BiPkSVJb.js → vue3-json-viewer-B1fiyuLU.js} +100 -100
- package/dist/vue3-xml-viewer.common-qOUjnppK.js +759 -0
- package/package.json +3 -3
- package/src/components/AppLink.vue +1 -1
- package/src/components/ResourceAccordion/MapContainer.client.vue +5 -2
- package/src/components/ResourceAccordion/Pmtiles.client.vue +11 -4
- package/src/components/ResourceAccordion/Preview.vue +1 -1
- package/src/components/ResourceAccordion/ResourceAccordion.vue +1 -1
- package/src/components/ResourceAccordion/SchemaBadge.vue +1 -1
- package/src/components/ResourceAccordion/Swagger.client.vue +1 -0
- package/src/components/SmallChart.vue +44 -23
- package/src/functions/api.types.ts +4 -4
- package/src/functions/dates.ts +3 -3
- package/src/functions/matomo.ts +1 -0
- package/src/functions/never.ts +3 -0
- package/src/main.ts +1 -0
- package/dist/Pmtiles.client-CCMKYGsj.js +0 -22377
- package/dist/Swagger.client-Ci_pwa2Z.js +0 -4
- package/dist/main-BGN65wY4.js +0 -100461
- package/dist/vue3-xml-viewer.common-ARb4d9zr.js +0 -5443
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagouv/components-next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/main.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"lint": "eslint . --fix",
|
|
19
19
|
"format": "prettier --write src/",
|
|
20
20
|
"css": "tailwindcss -i ./assets/main.css -o ./dist/components.css --minify --optimize",
|
|
21
|
-
"preversion": "npm run build
|
|
21
|
+
"preversion": "npm run build && npm run css",
|
|
22
22
|
"publish-stable": "npm publish --access public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"chart.js": "^4.4.8",
|
|
29
29
|
"dompurify": "^3.2.5",
|
|
30
30
|
"geopf-extensions-openlayers": "^1.0.0-beta.5",
|
|
31
|
-
"maplibre-gl": "^5.
|
|
31
|
+
"maplibre-gl": "^5.6.2",
|
|
32
32
|
"ofetch": "^1.4.1",
|
|
33
33
|
"ol": "^10.6.1",
|
|
34
34
|
"pdf-vue3": "^1.0.12",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<script setup lang = "ts">
|
|
18
|
-
import { onMounted, ref } from 'vue'
|
|
18
|
+
import { onMounted, ref, useTemplateRef } from 'vue'
|
|
19
19
|
import { useI18n } from 'vue-i18n'
|
|
20
20
|
import { RiErrorWarningLine } from '@remixicon/vue'
|
|
21
21
|
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
GeoportalZoom,
|
|
33
33
|
LayerImport,
|
|
34
34
|
LayerSwitcher,
|
|
35
|
+
// @ts-expect-error no types provided
|
|
35
36
|
} from 'geopf-extensions-openlayers'
|
|
36
37
|
|
|
37
38
|
import SimpleBanner from '../SimpleBanner.vue'
|
|
@@ -42,7 +43,7 @@ const props = defineProps<{ resource: Resource }>()
|
|
|
42
43
|
const { t } = useI18n()
|
|
43
44
|
|
|
44
45
|
let map = null
|
|
45
|
-
const mapRef =
|
|
46
|
+
const mapRef = useTemplateRef('mapRef')
|
|
46
47
|
const hasError = ref(false)
|
|
47
48
|
|
|
48
49
|
async function displayMap() {
|
|
@@ -53,6 +54,7 @@ async function displayMap() {
|
|
|
53
54
|
|
|
54
55
|
CRS.load()
|
|
55
56
|
map = new Map({
|
|
57
|
+
// @ts-expect-error null is not happening during onMount
|
|
56
58
|
target: mapRef.value,
|
|
57
59
|
layers: [
|
|
58
60
|
new TileLayer({
|
|
@@ -117,6 +119,7 @@ async function displayMap() {
|
|
|
117
119
|
hasError.value = true
|
|
118
120
|
}
|
|
119
121
|
else {
|
|
122
|
+
// @ts-expect-error no typing from library
|
|
120
123
|
const layerInfo = layerImport._getCapResponseWMSLayers.filter(layer => layer.Name == props.resource.title)[0]
|
|
121
124
|
layerImport._addGetCapWMSLayer(layerInfo)
|
|
122
125
|
}
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
</template>
|
|
53
53
|
|
|
54
54
|
<script setup lang="ts">
|
|
55
|
-
import { computed, onMounted, ref } from 'vue'
|
|
55
|
+
import { computed, onMounted, ref, useTemplateRef } from 'vue'
|
|
56
56
|
import { useI18n } from 'vue-i18n'
|
|
57
57
|
import { RiErrorWarningLine, RiExternalLinkFill } from '@remixicon/vue'
|
|
58
58
|
import { Protocol, PMTiles } from 'pmtiles'
|
|
@@ -60,6 +60,7 @@ import maplibregl from 'maplibre-gl'
|
|
|
60
60
|
import DOMPurify from 'dompurify'
|
|
61
61
|
import { useComponentsConfig } from '../../config'
|
|
62
62
|
import { useFormatDate } from '../../functions/dates'
|
|
63
|
+
import { throwOnNever } from '../../functions/never'
|
|
63
64
|
import type { Resource } from '../../types/resources'
|
|
64
65
|
import BrandedButton from '../BrandedButton.vue'
|
|
65
66
|
import styleVector from '../../../assets/json/vector.json'
|
|
@@ -74,12 +75,12 @@ const { formatDate } = useFormatDate()
|
|
|
74
75
|
const config = useComponentsConfig()
|
|
75
76
|
|
|
76
77
|
const hasError = ref(false)
|
|
77
|
-
const pmtilesUrl = computed(() => props.resource.extras['analysis:parsing:pmtiles_url'])
|
|
78
|
+
const pmtilesUrl = computed(() => props.resource.extras['analysis:parsing:pmtiles_url'] as string)
|
|
78
79
|
const pmtilesViewerUrl = computed(() => {
|
|
79
80
|
return config.pmtilesViewerBaseUrl ? `${config.pmtilesViewerBaseUrl}${encodeURIComponent(pmtilesUrl.value)}` : null
|
|
80
81
|
})
|
|
81
82
|
|
|
82
|
-
const lastUpdate = computed(() => formatDate(props.resource.extras['analysis:parsing:finished_at']))
|
|
83
|
+
const lastUpdate = computed(() => formatDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined))
|
|
83
84
|
|
|
84
85
|
const container = useTemplateRef('containerRef')
|
|
85
86
|
|
|
@@ -94,7 +95,9 @@ async function displayMap() {
|
|
|
94
95
|
|
|
95
96
|
p.getHeader().then((h) => {
|
|
96
97
|
const map = new maplibregl.Map({
|
|
98
|
+
// @ts-expect-error only null before mount
|
|
97
99
|
container: container.value, // container id
|
|
100
|
+
// @ts-expect-error TODO: type JSON
|
|
98
101
|
style: styleVector,
|
|
99
102
|
zoom: h.maxZoom - 2,
|
|
100
103
|
center: [h.centerLon, h.centerLat],
|
|
@@ -106,6 +109,7 @@ async function displayMap() {
|
|
|
106
109
|
closeOnClick: false,
|
|
107
110
|
})
|
|
108
111
|
|
|
112
|
+
// @ts-expect-error TODO: add type from library
|
|
109
113
|
function showMapPopup(e) {
|
|
110
114
|
if (!e.features || !e.features[0])
|
|
111
115
|
popup.remove()
|
|
@@ -125,7 +129,7 @@ async function displayMap() {
|
|
|
125
129
|
url: `pmtiles://${pmtilesUrl.value}`,
|
|
126
130
|
attribution: '© <a href="https://openstreetmap.org">OpenStreetMap</a>',
|
|
127
131
|
})
|
|
128
|
-
|
|
132
|
+
// @ts-expect-error not typed from library
|
|
129
133
|
metadata.tilestats.layers.forEach((layer) => {
|
|
130
134
|
const typeLayer = computed(() => {
|
|
131
135
|
switch (layer.geometry) {
|
|
@@ -136,6 +140,7 @@ async function displayMap() {
|
|
|
136
140
|
case 'LineString':
|
|
137
141
|
return `line`
|
|
138
142
|
default:
|
|
143
|
+
// @ts-expect-error no other geometries ?
|
|
139
144
|
throwOnNever(layer.geometry, 'Unsupported geometry')
|
|
140
145
|
return ''
|
|
141
146
|
}
|
|
@@ -144,6 +149,7 @@ async function displayMap() {
|
|
|
144
149
|
'id': layer.layer,
|
|
145
150
|
'source': 'pmtiles_source',
|
|
146
151
|
'source-layer': layer.layer,
|
|
152
|
+
// @ts-expect-error `''` (empty string) shouldn't happen (see `throwOnNever`)
|
|
147
153
|
'type': typeLayer.value,
|
|
148
154
|
'paint': {
|
|
149
155
|
[`${typeLayer.value}-color`]: 'steelblue',
|
|
@@ -151,6 +157,7 @@ async function displayMap() {
|
|
|
151
157
|
},
|
|
152
158
|
})
|
|
153
159
|
map.on('mousemove', layer.layer, showMapPopup)
|
|
160
|
+
// @ts-expect-error doesn't exist ?
|
|
154
161
|
map.on('touchmove', layer.layer, showMapPopup)
|
|
155
162
|
map.on('click', layer.layer, showMapPopup)
|
|
156
163
|
map.on('mouseleave', layer.layer, showMapPopup)
|
|
@@ -199,7 +199,7 @@ function sortByField(col: string) {
|
|
|
199
199
|
getTableInfos(currentPage.value, sortConfig.value)
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
-
const lastUpdate = computed(() => formatDate(props.resource.extras['analysis:parsing:finished_at']))
|
|
202
|
+
const lastUpdate = computed(() => formatDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined))
|
|
203
203
|
|
|
204
204
|
onMounted(() => {
|
|
205
205
|
getTableInfos(currentPage.value)
|
|
@@ -492,7 +492,7 @@ const communityResource = computed<CommunityResource | null>(() => {
|
|
|
492
492
|
const owner = computed(() => communityResource.value ? getOwnerName(communityResource.value) : null)
|
|
493
493
|
|
|
494
494
|
const lastUpdate = props.resource.last_modified
|
|
495
|
-
const conversionsLastUpdate = computed(() => formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at']))
|
|
495
|
+
const conversionsLastUpdate = computed(() => formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined))
|
|
496
496
|
const availabilityChecked = props.resource.extras && 'check:available' in props.resource.extras
|
|
497
497
|
|
|
498
498
|
const unavailable = availabilityChecked && props.resource.extras['check:available'] === false
|
|
@@ -121,7 +121,7 @@ const title = computed(() => {
|
|
|
121
121
|
return props.resource.schema.name || props.resource.schema.url
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
const validataErrors = computed<Array<ValidataError>>(() => props.resource.extras['validation-report:errors'] || [])
|
|
124
|
+
const validataErrors = computed<Array<ValidataError>>(() => props.resource.extras['validation-report:errors'] as Array<ValidataError> || [])
|
|
125
125
|
const validataWarnings = computed(() => validataErrors.value.filter(error => [''].includes(error.code)))
|
|
126
126
|
const validataBodyErrors = computed(() => validataErrors.value.filter(error => ['#body', '#cell', '#content', '#row', '#table'].some(tag => error.tags.includes(tag))))
|
|
127
127
|
const validataStructureErrors = computed(() => validataErrors.value.filter(error => ['#head', '#structure', '#header'].some(tag => error.tags.includes(tag))))
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
23
|
<script setup lang="ts">
|
|
24
|
-
import {
|
|
24
|
+
import type { ChartOptions, ScriptableLineSegmentContext } from 'chart.js'
|
|
25
|
+
import Chart from 'chart.js/auto'
|
|
25
26
|
import { computed, onMounted, ref, useTemplateRef, watchEffect } from 'vue'
|
|
26
27
|
|
|
27
28
|
const LIGHT_COLOR = '#B6CFFB'
|
|
@@ -43,7 +44,7 @@ const props = withDefaults(defineProps<{
|
|
|
43
44
|
width: 120,
|
|
44
45
|
})
|
|
45
46
|
|
|
46
|
-
const last = (ctx, value) => {
|
|
47
|
+
const last = (ctx: ScriptableLineSegmentContext, value: unknown) => {
|
|
47
48
|
return ctx.p1DataIndex === months.value.length - 1 ? value : null
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -63,27 +64,45 @@ const data = computed(() => {
|
|
|
63
64
|
const months = computed(() => Object.keys(data.value))
|
|
64
65
|
const values = computed(() => Object.values(data.value))
|
|
65
66
|
|
|
66
|
-
const additionalDatasetConfig = computed
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
const additionalDatasetConfig = computed<{
|
|
68
|
+
type: 'bar'
|
|
69
|
+
barPercentage: number
|
|
70
|
+
categoryPercentage: number
|
|
71
|
+
backgroundColor: Array<string>
|
|
72
|
+
} | {
|
|
73
|
+
type: 'line'
|
|
74
|
+
segment?: {
|
|
75
|
+
borderColor: (ctx: ScriptableLineSegmentContext) => string
|
|
76
|
+
borderDash: (ctx: ScriptableLineSegmentContext) => Array<number>
|
|
74
77
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
} | object>(() => {
|
|
79
|
+
if (props.type === 'bar') {
|
|
80
|
+
return {
|
|
81
|
+
type: 'bar',
|
|
82
|
+
barPercentage: 1,
|
|
83
|
+
categoryPercentage: 0.9,
|
|
84
|
+
// Change the color of the last bar only
|
|
85
|
+
backgroundColor: months.value.map((_value, index) => index === months.value.length - 1 ? (props.lastWithLowEmphasis ? LIGHT_COLOR_WITH_OPACITY : COLOR) : LIGHT_COLOR),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (props.type === 'line') {
|
|
90
|
+
if (props.lastWithLowEmphasis) {
|
|
91
|
+
return {
|
|
92
|
+
type: 'line',
|
|
93
|
+
segment: {
|
|
94
|
+
borderColor: (ctx: ScriptableLineSegmentContext) => last(ctx, COLOR_WITH_OPACITY) || COLOR,
|
|
95
|
+
borderDash: (ctx: ScriptableLineSegmentContext) => last(ctx, [3, 3]) || [6, 0],
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
type: 'line',
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {}
|
|
105
|
+
})
|
|
87
106
|
|
|
88
107
|
const getMonthYear = (dateAsString: string): string => {
|
|
89
108
|
const date = new Date(dateAsString)
|
|
@@ -95,6 +114,7 @@ const startDate = computed(() => months.value.length ? getMonthYear(months.value
|
|
|
95
114
|
const endDate = computed(() => months.value.length ? getMonthYear(months.value[months.value.length - 1]) : null)
|
|
96
115
|
|
|
97
116
|
const OPTIONS = {
|
|
117
|
+
// @ts-expect-error animation can be `true` but the typing is not expecting it
|
|
98
118
|
animation: true,
|
|
99
119
|
devicePixelRatio: 1,
|
|
100
120
|
responsive: false,
|
|
@@ -155,8 +175,9 @@ watchEffect(() => {
|
|
|
155
175
|
chart.value = new Chart(context.value, {
|
|
156
176
|
data: {
|
|
157
177
|
labels: months.value,
|
|
158
|
-
datasets: [{ data: values.value,
|
|
178
|
+
datasets: [{ data: values.value, ...additionalDatasetConfig.value }],
|
|
159
179
|
},
|
|
180
|
+
// @ts-expect-error animation type should allow `true`
|
|
160
181
|
options: OPTIONS,
|
|
161
182
|
})
|
|
162
183
|
})
|
|
@@ -3,15 +3,15 @@ import type { ComputedRef, Ref, WatchSource } from 'vue'
|
|
|
3
3
|
export type UseFetchOptions<DataT> = {
|
|
4
4
|
key?: string
|
|
5
5
|
method?: string
|
|
6
|
-
query?:
|
|
7
|
-
params?:
|
|
8
|
-
body?: RequestInit['body'] | Record<string,
|
|
6
|
+
query?: Record<string, unknown>
|
|
7
|
+
params?: Record<string, unknown>
|
|
8
|
+
body?: RequestInit['body'] | Record<string, unknown>
|
|
9
9
|
headers?: Record<string, string> | [key: string, value: string][] | Headers
|
|
10
10
|
baseURL?: string
|
|
11
11
|
server?: boolean
|
|
12
12
|
lazy?: boolean
|
|
13
13
|
immediate?: boolean
|
|
14
|
-
getCachedData?: (key: string, nuxtApp:
|
|
14
|
+
getCachedData?: (key: string, nuxtApp: unknown) => DataT
|
|
15
15
|
deep?: boolean
|
|
16
16
|
dedupe?: 'cancel' | 'defer'
|
|
17
17
|
default?: () => DataT
|
package/src/functions/dates.ts
CHANGED
|
@@ -5,7 +5,7 @@ const SECONDS_IN_A_DAY = 3600 * 24
|
|
|
5
5
|
export function useFormatDate() {
|
|
6
6
|
const { t, locale } = useI18n()
|
|
7
7
|
|
|
8
|
-
const formatDate = (date: Date | string | null, options: Intl.DateTimeFormatOptions = {}) => {
|
|
8
|
+
const formatDate = (date: Date | string | null | undefined, options: Intl.DateTimeFormatOptions = {}) => {
|
|
9
9
|
if (!date) {
|
|
10
10
|
return ''
|
|
11
11
|
}
|
|
@@ -20,7 +20,7 @@ export function useFormatDate() {
|
|
|
20
20
|
* Format date as relative from now.
|
|
21
21
|
* It displays "today" or Intl.RelativeTimeFormat content, based on date.
|
|
22
22
|
*/
|
|
23
|
-
const formatFromNow = (date: Date | string | null) => {
|
|
23
|
+
const formatFromNow = (date: Date | string | null | undefined) => {
|
|
24
24
|
if (!date) {
|
|
25
25
|
return ''
|
|
26
26
|
}
|
|
@@ -65,7 +65,7 @@ export function useFormatDate() {
|
|
|
65
65
|
* Format date relative form now if date is less than a month ago.
|
|
66
66
|
* Otherwise, show a formatted date.
|
|
67
67
|
*/
|
|
68
|
-
const formatRelativeIfRecentDate = (date: Date | string | null, options: Intl.DateTimeFormatOptions = {}) => {
|
|
68
|
+
const formatRelativeIfRecentDate = (date: Date | string | null | undefined, options: Intl.DateTimeFormatOptions = {}) => {
|
|
69
69
|
if (!date) {
|
|
70
70
|
return ''
|
|
71
71
|
}
|
package/src/functions/matomo.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -56,6 +56,7 @@ export * from './functions/datasets'
|
|
|
56
56
|
export * from './functions/owned'
|
|
57
57
|
export * from './functions/helpers'
|
|
58
58
|
export * from './functions/matomo'
|
|
59
|
+
export * from './functions/never'
|
|
59
60
|
export * from './functions/schemas'
|
|
60
61
|
export * from './functions/markdown'
|
|
61
62
|
|