@datagouv/components-next 1.0.2-dev.128 → 1.0.2-dev.129
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-BrjISlaZ.js → Datafair.client-CFl7MKdB.js} +1 -1
- package/dist/{JsonPreview.client-DivFAnbN.js → JsonPreview.client-CowJU7XP.js} +2 -2
- package/dist/{MapContainer.client-Cq8tNLZZ.js → MapContainer.client-CgdBWq2S.js} +2 -2
- package/dist/{PdfPreview.client-BNBgLsK2.js → PdfPreview.client-Dm4l4fyb.js} +2 -2
- package/dist/{Pmtiles.client-CQi5Rw8W.js → Pmtiles.client-DsjzH41p.js} +695 -695
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-C3dDzrIr.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BgFVrfFi.js} +1 -1
- package/dist/{XmlPreview.client-XCsNvnsZ.js → XmlPreview.client-DBceFnA1.js} +3 -3
- package/dist/components-next.js +106 -104
- package/dist/{index-CXUamc8Z.js → index-DWmJJEjk.js} +1 -1
- package/dist/{leaflet-src-BRKv9Ksv.js → leaflet-src-CGmV0V-K.js} +1 -1
- package/dist/{main-DKu5SOAl.js → main-CQREzlRN.js} +3972 -3961
- package/dist/{vue3-xml-viewer.common-BIaEIFYG.js → vue3-xml-viewer.common-d08lX8ER.js} +1 -1
- package/package.json +1 -1
- package/src/components/Chart/ChartViewer.vue +10 -9
- package/src/components/Chart/ChartViewerWrapper.vue +20 -16
- package/src/components/TabularExplorer/TabularExplorer.vue +4 -9
- package/src/components/TabularExplorer/types.ts +5 -2
- package/src/functions/charts.ts +12 -1
- package/src/functions/tabular.ts +9 -0
- package/src/functions/tabularApi.ts +1 -43
- package/src/main.ts +6 -1
- package/src/types/visualizations.ts +4 -0
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ const props = defineProps<{
|
|
|
22
22
|
chart: Chart | ChartForApi
|
|
23
23
|
series: {
|
|
24
24
|
data: Record<string, Array<Record<string, unknown>>>
|
|
25
|
-
columns: Record<string, Array<string>>
|
|
25
|
+
columns: Record<string, Array<{ name: string, type: string }>>
|
|
26
26
|
}
|
|
27
27
|
}>()
|
|
28
28
|
|
|
@@ -32,7 +32,7 @@ let echartsInstance: EChartsType | null = null
|
|
|
32
32
|
|
|
33
33
|
function mapXAxisType(xAxis: XAxis | XAxisForm): 'category' | 'value' {
|
|
34
34
|
if (!xAxis) return 'category'
|
|
35
|
-
return
|
|
35
|
+
return xAxis.type === 'continuous' ? 'value' : 'category'
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function buildYAxisFormatter(yAxis: YAxis): ((value: number) => string) | undefined {
|
|
@@ -53,7 +53,8 @@ const echartsOption = computed(() => {
|
|
|
53
53
|
const yColumn = s.aggregate_y ? `${s.column_y}__${s.aggregate_y}` : s.column_y
|
|
54
54
|
const resourceId = s.resource_id
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
const resourceColumns = props.series.columns[resourceId]
|
|
57
|
+
if (!xColumn || !yColumn || !resourceId || !s.type || !props.series.data[resourceId] || !resourceColumns) {
|
|
57
58
|
return null
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -110,7 +111,7 @@ const echartsOption = computed(() => {
|
|
|
110
111
|
return {
|
|
111
112
|
series: {
|
|
112
113
|
type: s.type === 'histogram' ? 'bar' : 'line',
|
|
113
|
-
dimensions: s.aggregate_y ? [xColumn, yColumn] :
|
|
114
|
+
dimensions: s.aggregate_y ? [xColumn, yColumn] : resourceColumns.map(c => c.name),
|
|
114
115
|
name: yColumn,
|
|
115
116
|
encode: {
|
|
116
117
|
x: xColumn,
|
|
@@ -119,7 +120,7 @@ const echartsOption = computed(() => {
|
|
|
119
120
|
} as LineSeriesOption | BarSeriesOption,
|
|
120
121
|
data: {
|
|
121
122
|
source: sortedData,
|
|
122
|
-
dimensions: s.aggregate_y ? [xColumn, yColumn] :
|
|
123
|
+
dimensions: s.aggregate_y ? [xColumn, yColumn] : resourceColumns.map(c => c.name),
|
|
123
124
|
},
|
|
124
125
|
}
|
|
125
126
|
})
|
|
@@ -137,10 +138,10 @@ const echartsOption = computed(() => {
|
|
|
137
138
|
|
|
138
139
|
return {
|
|
139
140
|
dataset: [...seriesData.data],
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
left: 'center',
|
|
141
|
+
textStyle: {
|
|
142
|
+
fontFamily: 'Marianne, arial, sans-serif',
|
|
143
143
|
},
|
|
144
|
+
color: '#000091',
|
|
144
145
|
tooltip: {
|
|
145
146
|
trigger: 'axis' as const,
|
|
146
147
|
formatter: (params: Array<{ value: Record<string, unknown>, axisValueLabel: string, seriesName: string }>) => {
|
|
@@ -154,7 +155,7 @@ const echartsOption = computed(() => {
|
|
|
154
155
|
},
|
|
155
156
|
},
|
|
156
157
|
legend: {
|
|
157
|
-
show:
|
|
158
|
+
show: false,
|
|
158
159
|
bottom: 0,
|
|
159
160
|
},
|
|
160
161
|
grid: {
|
|
@@ -18,22 +18,20 @@
|
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
20
|
<script setup lang="ts">
|
|
21
|
-
import { reactive, ref, watch } from 'vue'
|
|
21
|
+
import { computed, reactive, ref, watch } from 'vue'
|
|
22
22
|
import ChartViewer from './ChartViewer.vue'
|
|
23
23
|
import LoadingBlock from '../../components/LoadingBlock.vue'
|
|
24
24
|
import { useComponentsConfig } from '../../config'
|
|
25
25
|
import { fetchTabularData, useGetProfile } from '../../functions/tabularApi'
|
|
26
|
-
import type { Chart, ChartForApi } from '../../types/visualizations'
|
|
26
|
+
import type { Chart, ChartForApi, ColumnsDefinition } from '../../types/visualizations'
|
|
27
27
|
import { useTranslation } from '../../composables/useTranslation'
|
|
28
|
+
import { watchDebounced } from '@vueuse/shared'
|
|
29
|
+
import { buildColumnsFromProfile } from '../../functions/charts'
|
|
28
30
|
|
|
29
31
|
const props = defineProps<{
|
|
30
32
|
chart: Chart | ChartForApi
|
|
31
33
|
}>()
|
|
32
34
|
|
|
33
|
-
const emit = defineEmits<{
|
|
34
|
-
columns: [columns: Record<string, Array<string>>]
|
|
35
|
-
}>()
|
|
36
|
-
|
|
37
35
|
const { t } = useTranslation()
|
|
38
36
|
const config = useComponentsConfig()
|
|
39
37
|
const getProfile = useGetProfile()
|
|
@@ -45,12 +43,18 @@ const pendingOperations = ref(0)
|
|
|
45
43
|
|
|
46
44
|
const series = reactive<{
|
|
47
45
|
data: Record<string, Array<Record<string, unknown>>>
|
|
48
|
-
columns:
|
|
46
|
+
columns: ColumnsDefinition
|
|
49
47
|
}>({
|
|
50
48
|
data: {},
|
|
51
49
|
columns: {},
|
|
52
50
|
})
|
|
53
51
|
|
|
52
|
+
const resourceIds = computed(() => {
|
|
53
|
+
return props.chart.series
|
|
54
|
+
.filter(s => s.resource_id)
|
|
55
|
+
.map(s => s.resource_id)
|
|
56
|
+
})
|
|
57
|
+
|
|
54
58
|
async function fetchSeriesProfile() {
|
|
55
59
|
pendingOperations.value++
|
|
56
60
|
status.value = 'pending'
|
|
@@ -78,7 +82,7 @@ async function fetchSeriesProfile() {
|
|
|
78
82
|
.map(r => r.value)
|
|
79
83
|
series.columns = Object.fromEntries(results.map(result => [
|
|
80
84
|
result.id,
|
|
81
|
-
result.profile
|
|
85
|
+
buildColumnsFromProfile(result.profile),
|
|
82
86
|
]))
|
|
83
87
|
}
|
|
84
88
|
catch (err) {
|
|
@@ -86,6 +90,7 @@ async function fetchSeriesProfile() {
|
|
|
86
90
|
status.value = 'error'
|
|
87
91
|
console.error(err)
|
|
88
92
|
series.columns = {}
|
|
93
|
+
series.data = {}
|
|
89
94
|
}
|
|
90
95
|
finally {
|
|
91
96
|
pendingOperations.value--
|
|
@@ -148,17 +153,16 @@ async function fetchSeriesData() {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
151
|
-
watch(
|
|
156
|
+
watch(resourceIds, async () => {
|
|
152
157
|
await fetchSeriesProfile()
|
|
153
|
-
}, { immediate: true
|
|
158
|
+
}, { immediate: true })
|
|
154
159
|
|
|
155
|
-
|
|
160
|
+
watchDebounced([
|
|
161
|
+
() => props.chart.series,
|
|
162
|
+
() => props.chart.x_axis.column_x,
|
|
163
|
+
], async () => {
|
|
156
164
|
await fetchSeriesData()
|
|
157
|
-
}, { immediate: true, deep: true })
|
|
158
|
-
|
|
159
|
-
watch(() => series.columns, () => {
|
|
160
|
-
emit('columns', series.columns)
|
|
161
|
-
})
|
|
165
|
+
}, { debounce: config.searchDebounce ?? 300, immediate: true, deep: true })
|
|
162
166
|
|
|
163
167
|
watch(pendingOperations, (count) => {
|
|
164
168
|
if (count === 0) {
|
|
@@ -613,7 +613,7 @@ import { useFetch } from '../../functions/api'
|
|
|
613
613
|
import { useComponentsConfig } from '../../config'
|
|
614
614
|
import { useTranslation } from '../../composables/useTranslation'
|
|
615
615
|
import { injectTabularProfile } from '../../composables/useTabularProfile'
|
|
616
|
-
import { buildTypeConfig, buildFormatConfig, humanizeFormat, GENERIC_FORMATS, hasFilterForColumn as _hasFilterForColumn, isTruthy, isFalsy } from '../../functions/tabular'
|
|
616
|
+
import { buildTypeConfig, buildFormatConfig, humanizeFormat, GENERIC_FORMATS, hasFilterForColumn as _hasFilterForColumn, isTruthy, isFalsy, resolveColumnType } from '../../functions/tabular'
|
|
617
617
|
import ClientOnly from '../ClientOnly.vue'
|
|
618
618
|
import SimpleBanner from '../SimpleBanner.vue'
|
|
619
619
|
import BrandedButton from '../BrandedButton.vue'
|
|
@@ -999,23 +999,18 @@ function toggleMobileFilterColumn(col: string) {
|
|
|
999
999
|
}
|
|
1000
1000
|
|
|
1001
1001
|
// Column type helpers
|
|
1002
|
-
function
|
|
1002
|
+
function getColumnTypeFromName(col: string): ColumnType {
|
|
1003
1003
|
const profile = profileData.value?.profile
|
|
1004
1004
|
if (!profile) return 'text'
|
|
1005
1005
|
const colInfo = profile.columns[col]
|
|
1006
1006
|
if (!colInfo) return 'text'
|
|
1007
|
-
|
|
1008
|
-
if (colInfo.format === 'year') return 'date'
|
|
1009
|
-
if (['date', 'datetime'].includes(colInfo.python_type)) return 'date'
|
|
1010
|
-
if (colInfo.python_type === 'bool') return 'boolean'
|
|
1011
|
-
if (profile.categorical.includes(col)) return 'categorical'
|
|
1012
|
-
return 'text'
|
|
1007
|
+
return resolveColumnType(colInfo, profile.categorical.includes(col))
|
|
1013
1008
|
}
|
|
1014
1009
|
|
|
1015
1010
|
const columnTypesMap = computed(() => {
|
|
1016
1011
|
const map: Record<string, ColumnType> = {}
|
|
1017
1012
|
for (const col of allColumns.value) {
|
|
1018
|
-
map[col] =
|
|
1013
|
+
map[col] = getColumnTypeFromName(col)
|
|
1019
1014
|
}
|
|
1020
1015
|
return map
|
|
1021
1016
|
})
|
|
@@ -19,6 +19,9 @@ export type TabularRow = Record<string, unknown> & { __id: number }
|
|
|
19
19
|
/** Response from /api/resources/{rid}/profile/ */
|
|
20
20
|
export type TabularProfileResponse = {
|
|
21
21
|
profile: TabularProfile
|
|
22
|
+
deleted_at: string | null
|
|
23
|
+
dataset_id: string
|
|
24
|
+
indexes: null
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export type TabularProfile = {
|
|
@@ -31,8 +34,8 @@ export type TabularProfile = {
|
|
|
31
34
|
categorical: string[]
|
|
32
35
|
total_lines: number
|
|
33
36
|
nb_duplicates: number
|
|
34
|
-
columns_fields:
|
|
35
|
-
columns_labels:
|
|
37
|
+
columns_fields: Record<string, TabularColumnInfo>
|
|
38
|
+
columns_labels: Record<string, TabularColumnInfo>
|
|
36
39
|
header_row_idx: number
|
|
37
40
|
heading_columns: number
|
|
38
41
|
trailing_columns: number
|
package/src/functions/charts.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { Chart, ChartForm, ChartForApi, Filter } from '../types/visualizations'
|
|
1
|
+
import type { Chart, ChartForm, ChartForApi, Filter, ColumnDefinition } from '../types/visualizations'
|
|
2
|
+
import type { TabularProfile } from '../components/TabularExplorer/types'
|
|
3
|
+
import { resolveColumnType } from './tabular'
|
|
2
4
|
|
|
3
5
|
export function toChartForm(chart: Chart) {
|
|
4
6
|
const seriesFilter = chart.series[0]?.filters as Filter | null
|
|
@@ -66,3 +68,12 @@ export function toChartApi(chartForm: ChartForm): ChartForApi {
|
|
|
66
68
|
extras: chartForm.extras,
|
|
67
69
|
}
|
|
68
70
|
}
|
|
71
|
+
|
|
72
|
+
export function buildColumnsFromProfile(profile: { profile: TabularProfile }): Array<ColumnDefinition> {
|
|
73
|
+
return profile.profile.header.map((name) => {
|
|
74
|
+
const colInfo = profile.profile.columns[name]
|
|
75
|
+
const isCategorical = profile.profile.categorical.includes(name)
|
|
76
|
+
const colType = resolveColumnType(colInfo ?? { python_type: 'unknown', format: undefined }, isCategorical)
|
|
77
|
+
return { name, type: colType }
|
|
78
|
+
})
|
|
79
|
+
}
|
package/src/functions/tabular.ts
CHANGED
|
@@ -45,6 +45,15 @@ export function buildTypeConfig(t: TranslationFunction): Record<ColumnType, Type
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
export function resolveColumnType(colInfo: { python_type: string, format?: string }, isCategorical: boolean): ColumnType {
|
|
49
|
+
if (['int', 'float'].includes(colInfo.python_type)) return 'number'
|
|
50
|
+
if (colInfo.format === 'year') return 'date'
|
|
51
|
+
if (['date', 'datetime'].includes(colInfo.python_type)) return 'date'
|
|
52
|
+
if (colInfo.python_type === 'bool') return 'boolean'
|
|
53
|
+
if (isCategorical) return 'categorical'
|
|
54
|
+
return 'text'
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
// csv-detective formats that carry no semantic meaning beyond the generic
|
|
49
58
|
// display type already resolved by `ColumnType` — these fall back to
|
|
50
59
|
// `buildTypeConfig` (Texte / Nombre / Date / Booléen) in the header.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch'
|
|
2
2
|
import { useComponentsConfig, type PluginConfig } from '../config'
|
|
3
3
|
import type { GenericFilter } from '../types/visualizations'
|
|
4
|
-
import type { SortConfig } from '../components/TabularExplorer/types'
|
|
4
|
+
import type { SortConfig, TabularProfileResponse } from '../components/TabularExplorer/types'
|
|
5
5
|
|
|
6
6
|
export type { SortConfig }
|
|
7
7
|
|
|
@@ -31,48 +31,6 @@ export type FetchTabularDataOptions = {
|
|
|
31
31
|
filters?: GenericFilter | undefined
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export type TabularProfileResponse = {
|
|
35
|
-
profile: {
|
|
36
|
-
header: Array<string>
|
|
37
|
-
columns: Record<string, {
|
|
38
|
-
score: number
|
|
39
|
-
format: string
|
|
40
|
-
python_type: string
|
|
41
|
-
}>
|
|
42
|
-
formats: Record<string, Array<string>>
|
|
43
|
-
profile: Record<string, {
|
|
44
|
-
tops: Array<{ count: number, value: string }>
|
|
45
|
-
nb_distinct: number
|
|
46
|
-
nb_missing_values: number
|
|
47
|
-
min?: number
|
|
48
|
-
max?: number
|
|
49
|
-
std?: number
|
|
50
|
-
mean?: number
|
|
51
|
-
}>
|
|
52
|
-
encoding: string
|
|
53
|
-
separator: string
|
|
54
|
-
categorical: Array<string>
|
|
55
|
-
total_lines: number
|
|
56
|
-
nb_duplicates: number
|
|
57
|
-
columns_fields: Record<string, {
|
|
58
|
-
score: number
|
|
59
|
-
format: string
|
|
60
|
-
python_type: string
|
|
61
|
-
}>
|
|
62
|
-
columns_labels: Record<string, {
|
|
63
|
-
score: number
|
|
64
|
-
format: string
|
|
65
|
-
python_type: string
|
|
66
|
-
}>
|
|
67
|
-
header_row_idx: number
|
|
68
|
-
heading_columns: number
|
|
69
|
-
trailing_columns: number
|
|
70
|
-
}
|
|
71
|
-
deleted_at: string | null
|
|
72
|
-
dataset_id: string
|
|
73
|
-
indexes: null
|
|
74
|
-
}
|
|
75
|
-
|
|
76
34
|
/**
|
|
77
35
|
* Call Tabular-api to get table content with options object
|
|
78
36
|
*/
|
package/src/main.ts
CHANGED
|
@@ -23,7 +23,8 @@ import type { Site } from './types/site'
|
|
|
23
23
|
import type { Weight, WellType } from './types/ui'
|
|
24
24
|
import type { User, UserReference } from './types/users'
|
|
25
25
|
import type { Report, ReportSubject, ReportReason } from './types/reports'
|
|
26
|
-
import type { Chart, ChartForm, ChartForApi, FilterCondition, Filter, AndFilters, GenericFilter, XAxisType, XAxisSortBy, SortDirection, XAxis, XAxisForm, UnitPosition, YAxis, DataSeriesType, DataSeries, DataSeriesForm } from './types/visualizations'
|
|
26
|
+
import type { Chart, ChartForm, ChartForApi, FilterCondition, Filter, AndFilters, GenericFilter, XAxisType, XAxisSortBy, SortDirection, XAxis, XAxisForm, UnitPosition, YAxis, DataSeriesType, DataSeries, DataSeriesForm, CombinedSort, ColumnDefinition, ColumnsDefinition } from './types/visualizations'
|
|
27
|
+
import type { ColumnType } from './components/TabularExplorer/types'
|
|
27
28
|
import type { GlobalSearchConfig, SearchType, SearchTypeConfig, SortOption, HiddenFilter, BuiltInFilterKey, DatasetSearchConfig, DatasetSearchFilters, DataserviceSearchConfig, DataserviceSearchFilters, ReuseSearchConfig, ReuseSearchFilters, OrganizationSearchConfig, OrganizationSearchFilters, TopicSearchConfig, TopicSearchFilters } from './types/search'
|
|
28
29
|
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
29
30
|
import { useSearchFilter } from './composables/useSearchFilter'
|
|
@@ -251,6 +252,10 @@ export type {
|
|
|
251
252
|
Chart,
|
|
252
253
|
ChartForm,
|
|
253
254
|
ChartForApi,
|
|
255
|
+
CombinedSort,
|
|
256
|
+
ColumnDefinition,
|
|
257
|
+
ColumnType,
|
|
258
|
+
ColumnsDefinition,
|
|
254
259
|
FilterCondition,
|
|
255
260
|
Filter,
|
|
256
261
|
AndFilters,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TabularAggregateType } from '../functions/tabularApi'
|
|
2
2
|
import type { Owned, OwnedWithId } from './owned'
|
|
3
|
+
import type { ColumnType } from '../components/TabularExplorer/types'
|
|
3
4
|
|
|
4
5
|
export type FilterCondition = 'exact' | 'differs' | 'is_null' | 'is_not_null' | 'greater' | 'less' | 'strictly_greater' | 'strictly_less'
|
|
5
6
|
export type Filter = {
|
|
@@ -87,3 +88,6 @@ export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organ
|
|
|
87
88
|
chart_type?: DataSeriesType | null
|
|
88
89
|
filter: GenericFilter | null
|
|
89
90
|
}
|
|
91
|
+
|
|
92
|
+
export type ColumnDefinition = { name: string, type: ColumnType }
|
|
93
|
+
export type ColumnsDefinition = Record<string, Array<ColumnDefinition>>
|