@datagouv/components-next 1.0.2-dev.4 → 1.0.2-dev.41

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.
Files changed (57) hide show
  1. package/dist/Datafair.client-BAokThtJ.js +30 -0
  2. package/dist/JsonPreview.client-DGiaDxVv.js +40 -0
  3. package/dist/{MapContainer.client-DjjvdKBp.js → MapContainer.client-BKGsAP0Y.js} +35 -38
  4. package/dist/{PdfPreview.client-CsvKU0Aq.js → PdfPreview.client-CGjP5ZYb.js} +822 -865
  5. package/dist/{Pmtiles.client-uqg1fwOl.js → Pmtiles.client-C1I7pwT5.js} +574 -579
  6. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-BlcvVwW8.js +61 -0
  7. package/dist/Swagger.client-U7ZDVUHL.js +4 -0
  8. package/dist/XmlPreview.client-CHUVVEH6.js +34 -0
  9. package/dist/components-next.css +3 -3
  10. package/dist/components-next.js +83 -86
  11. package/dist/components.css +1 -1
  12. package/dist/{index-PMeuFwWj.js → index-CzClB3i0.js} +1 -1
  13. package/dist/{main-ByqZlhiZ.js → main-CF7lWk6R.js} +31224 -30474
  14. package/dist/{vue3-xml-viewer.common-DFrGHXJC.js → vue3-xml-viewer.common-CAwAbUJl.js} +1 -1
  15. package/package.json +10 -8
  16. package/src/components/ActivityList/ActivityList.vue +0 -2
  17. package/src/components/Form/SearchableSelect.vue +2 -1
  18. package/src/components/Pagination.vue +8 -5
  19. package/src/components/ReadMore.vue +1 -1
  20. package/src/components/ResourceAccordion/Datafair.client.vue +4 -10
  21. package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -121
  22. package/src/components/ResourceAccordion/MapContainer.client.vue +7 -11
  23. package/src/components/ResourceAccordion/Metadata.vue +1 -2
  24. package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -103
  25. package/src/components/ResourceAccordion/Pmtiles.client.vue +5 -10
  26. package/src/components/ResourceAccordion/Preview.vue +6 -11
  27. package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
  28. package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
  29. package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
  30. package/src/components/ResourceAccordion/ResourceAccordion.vue +1 -2
  31. package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -115
  32. package/src/components/ResourceExplorer/ResourceExplorer.vue +21 -10
  33. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +24 -3
  34. package/src/components/Search/GlobalSearch.vue +29 -4
  35. package/src/composables/useResourceCapabilities.ts +1 -1
  36. package/src/config.ts +2 -0
  37. package/src/functions/datasets.ts +0 -17
  38. package/src/functions/resources.ts +56 -1
  39. package/src/functions/tabularApi.ts +7 -84
  40. package/src/main.ts +3 -24
  41. package/src/types/dataservices.ts +2 -0
  42. package/src/types/organizations.ts +1 -1
  43. package/src/types/pages.ts +0 -5
  44. package/src/types/posts.ts +2 -2
  45. package/src/types/reports.ts +3 -0
  46. package/src/types/search.ts +26 -1
  47. package/src/types/site.ts +5 -3
  48. package/src/types/users.ts +0 -1
  49. package/dist/Datafair.client-c1cUKkQR.js +0 -35
  50. package/dist/JsonPreview.client-CAs9XTCX.js +0 -87
  51. package/dist/Swagger.client-BGrkka3l.js +0 -4
  52. package/dist/XmlPreview.client-BWbKzLte.js +0 -79
  53. package/src/components/Chart/ChartViewer.vue +0 -152
  54. package/src/components/Chart/ChartViewerWrapper.vue +0 -194
  55. package/src/functions/pagination.ts +0 -9
  56. package/src/types/visualizations.ts +0 -84
  57. /package/assets/illustrations/{_microscope.svg → microscope.svg} +0 -0
@@ -1,152 +0,0 @@
1
- <template>
2
- <VChart
3
- class="w-full min-h-96"
4
- :option="echartsOption"
5
- autoresize
6
- />
7
- </template>
8
-
9
- <script setup lang="ts">
10
- import { format, use, type ComposeOption } from 'echarts/core'
11
- import { CanvasRenderer } from 'echarts/renderers'
12
- import { LineChart, BarChart, type BarSeriesOption, type LineSeriesOption } from 'echarts/charts'
13
- import { TitleComponent, TooltipComponent, LegendComponent, GridComponent, DatasetComponent } from 'echarts/components'
14
- import VChart from 'vue-echarts'
15
- import { computed } from 'vue'
16
- import { summarize } from '../../functions/helpers'
17
- import type { Chart, DataSeries, XAxis, YAxis, ChartForm, XAxisForm } from '../../types/visualizations'
18
-
19
- use([CanvasRenderer, LineChart, BarChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent, DatasetComponent])
20
-
21
- const props = defineProps<{
22
- chart: Chart | ChartForm
23
- series: {
24
- data: Record<string, Array<Record<string, unknown>>>
25
- columns: Record<string, Array<string>>
26
- }
27
- }>()
28
-
29
- function mapSeriesType(type: DataSeries['type']): 'line' | 'bar' {
30
- return (type ?? 'line') === 'histogram' ? 'bar' : 'line'
31
- }
32
-
33
- function mapXAxisType(xAxis: XAxis | XAxisForm): 'category' | 'value' {
34
- if (!xAxis) return 'category'
35
- return (xAxis.type ?? 'discrete') === 'continuous' ? 'value' : 'category'
36
- }
37
-
38
- function buildYAxisFormatter(yAxis: YAxis): ((value: number) => string) | undefined {
39
- return (value: number) => {
40
- const v = summarize(value)
41
- if (!yAxis.unit) return v
42
- if (yAxis.unit_position === 'prefix') return `${yAxis.unit} ${v}`
43
- return `${v} ${yAxis.unit}`
44
- }
45
- }
46
-
47
- const echartsOption = computed(() => {
48
- const seriesCount = props.chart.series.length
49
- if (!props.chart.series || seriesCount === 0) return
50
-
51
- // Create series configuration with data mapping
52
- const seriesData = props.chart.series.map((s) => {
53
- const xColumn = s.column_x_name_override ?? props.chart.x_axis.column_x
54
- const yColumn = s.aggregate_y ? `${s.column_y}__${s.aggregate_y}` : s.column_y
55
- const resourceId = s.resource_id
56
- const seriesType = s.type
57
-
58
- if (!xColumn || !yColumn || !resourceId || !seriesType || !props.series.data[resourceId] || !props.series.columns[resourceId]) {
59
- return null
60
- }
61
-
62
- // Sort data before passing to ECharts to avoid transform issues
63
- const sortedData = [...props.series.data[resourceId]]
64
- const sortBy = props.chart.x_axis.sort_x_by
65
- const sortDirection = props.chart.x_axis.sort_x_direction ?? 'asc'
66
-
67
- if (sortBy && sortDirection && props.chart.x_axis.column_x) {
68
- const sortKey = sortBy === 'axis_x' ? xColumn : yColumn
69
- sortedData.sort((a, b) => {
70
- const valA = a[sortKey] as number
71
- const valB = b[sortKey] as number
72
- if (valA < valB) return sortDirection === 'asc' ? -1 : 1
73
- if (valA > valB) return sortDirection === 'asc' ? 1 : -1
74
- return 0
75
- })
76
- }
77
-
78
- return {
79
- series: {
80
- type: mapSeriesType(seriesType),
81
- dimensions: s.aggregate_y ? [xColumn, yColumn] : props.series.columns[resourceId],
82
- name: s.column_y,
83
- encode: {
84
- x: xColumn,
85
- y: yColumn,
86
- },
87
- } as LineSeriesOption | BarSeriesOption,
88
- data: {
89
- source: sortedData,
90
- dimensions: s.aggregate_y ? [xColumn, yColumn] : props.series.columns[resourceId],
91
- },
92
- }
93
- }).filter(Boolean).reduce((acc: { series: Array<LineSeriesOption | BarSeriesOption>, data: Array<Record<string, unknown>> }, curr) => {
94
- if (curr) {
95
- acc.series.push(curr.series)
96
- acc.data.push(curr.data)
97
- }
98
- return acc
99
- }, {
100
- series: [],
101
- data: [],
102
- })
103
-
104
- return {
105
- dataset: [...seriesData.data],
106
- title: {
107
- text: props.chart.title,
108
- left: 'center',
109
- },
110
- tooltip: {
111
- trigger: 'axis' as const,
112
- formatter: (params: Array<{ value: Record<string, unknown>, axisValueLabel: string, seriesName: string }>) => {
113
- let tooltip = ''
114
- for (const param of params) {
115
- const keys = Object.keys(param.value)
116
- const col = keys.find(key => key.startsWith(param.seriesName))!
117
- const formatter = new Intl.NumberFormat('fr-FR')
118
- tooltip += `${format.encodeHTML(param.axisValueLabel)}: <strong>${formatter.format(Number(param.value[col]))}</strong><br>`
119
- }
120
- return tooltip
121
- },
122
- },
123
- legend: {
124
- bottom: 0,
125
- },
126
- grid: {
127
- top: 60,
128
- bottom: 40,
129
- left: 20,
130
- right: 20,
131
- containLabel: true,
132
- },
133
- xAxis: {
134
- type: mapXAxisType(props.chart.x_axis),
135
- name: (props.chart.x_axis as XAxis).column_x,
136
- },
137
- yAxis: {
138
- type: 'value' as const,
139
- name: props.chart.y_axis.label ?? undefined,
140
- min: props.chart.y_axis.min ?? undefined,
141
- max: props.chart.y_axis.max ?? undefined,
142
- axisLabel: {
143
- formatter: buildYAxisFormatter(props.chart.y_axis),
144
- },
145
- },
146
- series: seriesData.series,
147
- } satisfies ComposeOption<
148
- | BarSeriesOption
149
- | LineSeriesOption
150
- >
151
- })
152
- </script>
@@ -1,194 +0,0 @@
1
- <template>
2
- <LoadingBlock
3
- :status="status"
4
- :data="series"
5
- >
6
- <template #default="{ data }">
7
- <ChartViewer
8
- :chart="chart"
9
- :series="data"
10
- />
11
- </template>
12
- <template #error>
13
- <div class="text-center py-8 text-gray-500">
14
- Une erreur est survenue lors du chargement des données du graphique.
15
- </div>
16
- </template>
17
- </LoadingBlock>
18
- </template>
19
-
20
- <script setup lang="ts">
21
- import { reactive, ref, watch } from 'vue'
22
- import ChartViewer from './ChartViewer.vue'
23
- import LoadingBlock from '../../components/LoadingBlock.vue'
24
- import { useComponentsConfig } from '../../config'
25
- import { fetchTabularData, useGetProfile, type TabularDataResponse, type TabularProfileResponse } from '../../functions/tabularApi'
26
- import type { Chart, ChartForm } from '../../types/visualizations'
27
-
28
- const chart = defineModel<Chart | ChartForm>({ required: true })
29
-
30
- const emit = defineEmits<{
31
- columns: [columns: Record<string, Array<string>>]
32
- }>()
33
-
34
- const config = useComponentsConfig()
35
- const getProfile = useGetProfile()
36
-
37
- // Loading and error states
38
- const status = ref<'idle' | 'pending' | 'success' | 'error'>('idle')
39
- const error = ref<Error | null>(null)
40
-
41
- // Dataset source for the chart
42
- const series = reactive<{
43
- data: Record<string, Array<Record<string, unknown>>>
44
- columns: Record<string, Array<string>>
45
- }>({
46
- data: {},
47
- columns: {},
48
- })
49
-
50
- async function fetchSeriesProfile() {
51
- status.value = 'pending'
52
- error.value = null
53
-
54
- try {
55
- if (chart.value.series.length === 0) {
56
- status.value = 'success'
57
- series.data = {}
58
- series.columns = {}
59
- return
60
- }
61
-
62
- // Fetch data for all series in parallel
63
- const fetchPromises = chart.value.series.map(async (serie) => {
64
- if (!serie.resource_id) return
65
- return {
66
- id: serie.resource_id,
67
- profile: await getProfile(serie.resource_id),
68
- }
69
- }).filter(Boolean) as Array<Promise<{
70
- id: string
71
- profile: TabularProfileResponse
72
- }>>
73
-
74
- const results = (await Promise.allSettled(fetchPromises))
75
- .filter(r => r.status === 'fulfilled')
76
- .map(r => r.value)
77
- series.columns = Object.fromEntries(results.map(result => [
78
- result.id,
79
- result.profile.profile.header,
80
- ]))
81
- if (results.length > 0) {
82
- const columns = results[0]?.profile.profile.header ?? []
83
- const firstColumn = columns.filter(c => c !== '__id')[0]
84
- if (!chart.value.x_axis.column_x && firstColumn) {
85
- chart.value.x_axis.column_x = firstColumn
86
- }
87
- }
88
- status.value = 'success'
89
- }
90
- catch (err) {
91
- error.value = err instanceof Error ? err : new Error('Failed to fetch series profile')
92
- status.value = 'error'
93
- console.log(err)
94
- series.columns = {}
95
- }
96
- }
97
-
98
- async function fetchSeriesData() {
99
- status.value = 'pending'
100
- error.value = null
101
-
102
- try {
103
- if (chart.value.series.length === 0 || !chart.value.x_axis.column_x) {
104
- status.value = 'success'
105
- series.data = {}
106
- return
107
- }
108
-
109
- // Fetch data for all series in parallel
110
- const fetchPromises = chart.value.series.map(async (serie) => {
111
- const xColumn = serie.column_x_name_override ?? chart.value.x_axis.column_x
112
- if (!xColumn || !serie.resource_id || !serie.column_y) return
113
- return {
114
- id: serie.resource_id,
115
- profile: await getProfile(serie.resource_id),
116
- data: await fetchTabularData(config, {
117
- columns: serie.aggregate_y ? undefined : [xColumn, serie.column_y],
118
- resourceId: serie.resource_id,
119
- page: 1,
120
- pageSize: 100,
121
- groupBy: xColumn,
122
- aggregation: serie.column_y && serie.aggregate_y
123
- ? {
124
- column: serie.column_y,
125
- type: serie.aggregate_y,
126
- }
127
- : undefined,
128
- }),
129
- }
130
- }).filter(Boolean) as Array<Promise<{
131
- id: string
132
- data: TabularDataResponse
133
- }>>
134
-
135
- const results = (await Promise.allSettled(fetchPromises))
136
- .filter(r => r.status === 'fulfilled')
137
- .map(r => r.value)
138
- // Transform data into echarts format
139
- series.data = Object.fromEntries(results.map(result => [
140
- result.id,
141
- result.data.data,
142
- ]))
143
- status.value = 'success'
144
- }
145
- catch (err) {
146
- error.value = err instanceof Error ? err : new Error('Failed to fetch series data')
147
- status.value = 'error'
148
- series.data = {}
149
- }
150
- }
151
-
152
- // Watch for changes in the chart or its series
153
- watch(() => chart.value.series, async () => {
154
- await fetchSeriesProfile()
155
- }, { immediate: true, deep: true })
156
-
157
- // Watch for changes in the chart or its series
158
- watch([() => chart.value.series, () => chart.value.x_axis.column_x], async () => {
159
- await fetchSeriesData()
160
- }, { immediate: true, deep: true })
161
-
162
- watch(() => series.columns, () => {
163
- emit('columns', series.columns)
164
- })
165
-
166
- /**
167
- * Combines data from multiple series into a single echarts dataset source
168
- */
169
- // function combineSeriesData(seriesData: Array<TabularDataResponse | null>): Array<Array<unknown>> {
170
- // if (!seriesData.length || seriesData.every(data => !data || !data.data || data.data.length === 0)) {
171
- // return []
172
- // }
173
-
174
- // // Get all unique columns from all series
175
- // const allColumns = Array.from(new Set(seriesData.flatMap(data =>
176
- // data?.data?.flatMap(Object.keys) || []
177
- // )))
178
-
179
- // // Build the source array with headers
180
- // const source: Array<Array<unknown>> = [allColumns]
181
-
182
- // // Add data rows - for simplicity, we'll use data from the first series
183
- // // In a real implementation, you'd want to merge/combine the data appropriately
184
- // const firstData = seriesData.find(data => data?.data?.length)?.data
185
- // if (firstData) {
186
- // firstData.forEach(row => {
187
- // const rowValues = allColumns.map(column => row[column])
188
- // source.push(rowValues)
189
- // })
190
- // }
191
-
192
- // return source
193
- // }
194
- </script>
@@ -1,9 +0,0 @@
1
- import { useRoute } from 'vue-router'
2
-
3
- export function getLink(page: number): string {
4
- const route = useRoute()
5
- const routePath = route.path
6
- const search = new URLSearchParams(route.query as Record<string, string>)
7
- search.set('page', page.toFixed(0))
8
- return `${routePath}?${search.toString()}`
9
- }
@@ -1,84 +0,0 @@
1
- import type { TabularAggregateType } from '../functions/tabularApi'
2
- import type { Owned, OwnedWithId } from './owned'
3
-
4
- export type FilterCondition = 'equal' | 'greater'
5
-
6
- export type Filter = {
7
- column: string
8
- condition: FilterCondition
9
- value?: string
10
- }
11
-
12
- export type AndFilters = {
13
- filters: Array<Filter | AndFilters>
14
- }
15
-
16
- export type GenericFilter = Filter | AndFilters
17
-
18
- export type XAxisType = 'discrete' | 'continuous'
19
-
20
- export type XAxisSortBy = 'axis_x' | 'axis_y'
21
-
22
- export type SortDirection = 'asc' | 'desc'
23
-
24
- export type XAxis = {
25
- column_x: string
26
- sort_x_by: XAxisSortBy | null
27
- sort_x_direction: SortDirection | null
28
- type: XAxisType
29
- }
30
-
31
- export type XAxisForm = Omit<XAxis, 'sort_x_by'> & { sort_x_by: XAxisSortBy | '' | null }
32
-
33
- export type UnitPosition = 'prefix' | 'suffix'
34
-
35
- export type YAxis = {
36
- min: number | null
37
- max: number | null
38
- label: string | null
39
- unit: string | null
40
- unit_position: UnitPosition | null
41
- }
42
-
43
- export type DataSeriesType = 'line' | 'histogram'
44
-
45
- export type DataSeries = {
46
- type: DataSeriesType
47
- column_y: string
48
- aggregate_y: TabularAggregateType | null
49
- resource_id: string
50
- column_x_name_override: string | null
51
- filters: GenericFilter | null
52
- }
53
-
54
- // Type for form where aggregate_y can be empty string for select binding
55
- export type DataSeriesForm = Omit<DataSeries, 'aggregate_y'> & { aggregate_y: TabularAggregateType | '' | null }
56
-
57
- export type Chart = Owned & {
58
- id: string
59
- title: string
60
- slug: string
61
- description: string
62
- private: boolean
63
- created_at: string
64
- last_modified: string
65
- deleted_at: string | null
66
- uri: string
67
- page: string
68
- x_axis: XAxis
69
- y_axis: YAxis
70
- series: Array<DataSeries>
71
- extras: Record<string, unknown>
72
- permissions: { delete: boolean, edit: boolean, read: boolean }
73
- metrics: {
74
- views: number
75
- }
76
- }
77
-
78
- export type ChartForApi = OwnedWithId & Pick<Chart, 'title' | 'description' | 'private' | 'x_axis' | 'y_axis' | 'series' | 'extras'>
79
-
80
- export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organization'> & {
81
- owned: OwnedWithId
82
- x_axis: XAxisForm
83
- series: Array<DataSeriesForm>
84
- }