@datagouv/components-next 1.0.2-dev.127 → 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.
Files changed (26) hide show
  1. package/dist/{Datafair.client-B1CFLBVW.js → Datafair.client-CFl7MKdB.js} +1 -1
  2. package/dist/{JsonPreview.client-DMal7Zvi.js → JsonPreview.client-CowJU7XP.js} +2 -2
  3. package/dist/{MapContainer.client-D4TU557F.js → MapContainer.client-CgdBWq2S.js} +2 -2
  4. package/dist/{PdfPreview.client-BPKxdMlu.js → PdfPreview.client-Dm4l4fyb.js} +2 -2
  5. package/dist/{Pmtiles.client-DW9JBIOy.js → Pmtiles.client-DsjzH41p.js} +1 -1
  6. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-B54_WCDL.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BgFVrfFi.js} +1 -1
  7. package/dist/{XmlPreview.client-DfIA3_I8.js → XmlPreview.client-DBceFnA1.js} +3 -3
  8. package/dist/components-next.js +158 -153
  9. package/dist/components.css +1 -1
  10. package/dist/{index-CtZYQyKo.js → index-DWmJJEjk.js} +1 -1
  11. package/dist/{leaflet-src-DcM2vBl8.js → leaflet-src-CGmV0V-K.js} +1 -1
  12. package/dist/{main-BOGKXwyT.js → main-CQREzlRN.js} +12210 -12030
  13. package/dist/{vue3-xml-viewer.common-DuOzEGKy.js → vue3-xml-viewer.common-d08lX8ER.js} +1 -1
  14. package/package.json +1 -1
  15. package/src/components/Chart/ChartViewer.vue +10 -9
  16. package/src/components/Chart/ChartViewerWrapper.vue +20 -16
  17. package/src/components/TabularExplorer/TabularCellPopover.vue +2 -2
  18. package/src/components/TabularExplorer/TabularExplorer.vue +215 -82
  19. package/src/components/TabularExplorer/TabularFilterContent.vue +15 -13
  20. package/src/components/TabularExplorer/TabularFilterPopover.vue +21 -26
  21. package/src/components/TabularExplorer/types.ts +14 -11
  22. package/src/functions/charts.ts +12 -1
  23. package/src/functions/tabular.ts +112 -1
  24. package/src/functions/tabularApi.ts +1 -43
  25. package/src/main.ts +6 -1
  26. package/src/types/visualizations.ts +4 -0
@@ -1,5 +1,5 @@
1
1
  /** Response from /api/resources/{rid}/data/ */
2
- export interface TabularDataResponse {
2
+ export type TabularDataResponse = {
3
3
  data: TabularRow[]
4
4
  meta: {
5
5
  page: number
@@ -17,11 +17,14 @@ export interface TabularDataResponse {
17
17
  export type TabularRow = Record<string, unknown> & { __id: number }
18
18
 
19
19
  /** Response from /api/resources/{rid}/profile/ */
20
- export interface TabularProfileResponse {
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
- export interface TabularProfile {
27
+ export type TabularProfile = {
25
28
  header: string[]
26
29
  columns: Record<string, TabularColumnInfo>
27
30
  formats: Record<string, string[]>
@@ -31,20 +34,20 @@ export interface TabularProfile {
31
34
  categorical: string[]
32
35
  total_lines: number
33
36
  nb_duplicates: number
34
- columns_fields: unknown
35
- columns_labels: unknown
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
39
42
  }
40
43
 
41
- export interface TabularColumnInfo {
44
+ export type TabularColumnInfo = {
42
45
  score: number
43
46
  format: string
44
47
  python_type: string
45
48
  }
46
49
 
47
- export interface TabularColumnProfile {
50
+ export type TabularColumnProfile = {
48
51
  tops: TabularTopValue[]
49
52
  nb_distinct: number
50
53
  nb_missing_values: number
@@ -54,14 +57,14 @@ export interface TabularColumnProfile {
54
57
  mean?: number
55
58
  }
56
59
 
57
- export interface TabularTopValue {
60
+ export type TabularTopValue = {
58
61
  value: string
59
62
  count: number
60
63
  }
61
64
 
62
65
  export type ColumnType = 'number' | 'categorical' | 'text' | 'date' | 'boolean'
63
66
 
64
- export interface ColumnFilters {
67
+ export type ColumnFilters = {
65
68
  in?: string[]
66
69
  exact?: string
67
70
  min?: number
@@ -72,12 +75,12 @@ export interface ColumnFilters {
72
75
 
73
76
  export type SortDirection = 'asc' | 'desc'
74
77
 
75
- export interface SortConfig {
78
+ export type SortConfig = {
76
79
  column: string
77
80
  direction: SortDirection
78
81
  }
79
82
 
80
- export interface BadgeStyle {
83
+ export type BadgeStyle = {
81
84
  backgroundColor: string
82
85
  color: string
83
86
  }
@@ -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
+ }
@@ -4,9 +4,24 @@ import {
4
4
  RiPriceTag3Line,
5
5
  RiText,
6
6
  RiCalendarLine,
7
+ RiCalendarEventLine,
8
+ RiTimeLine,
7
9
  RiCheckboxLine,
10
+ RiMapPin2Line,
11
+ RiGlobalLine,
12
+ RiFocus3Line,
13
+ RiFingerprintLine,
14
+ RiMailLine,
15
+ RiLinksLine,
16
+ RiPhoneLine,
17
+ RiUserLine,
18
+ RiMoneyEuroCircleLine,
19
+ RiPercentLine,
20
+ RiBracesLine,
21
+ RiCodeLine,
8
22
  } from '@remixicon/vue'
9
23
  import { useTranslation } from '../composables/useTranslation'
24
+ import type { TranslationFunction } from '../composables/useTranslation'
10
25
  import type { ColumnFilters, ColumnType } from '../components/TabularExplorer/types'
11
26
 
12
27
  export function hasFilterForColumn(filters: Record<string, ColumnFilters>, column: string): boolean {
@@ -15,7 +30,12 @@ export function hasFilterForColumn(filters: Record<string, ColumnFilters>, colum
15
30
  return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null)
16
31
  }
17
32
 
18
- export function buildTypeConfig(t: (s: string) => string): Record<ColumnType, { icon: Component, label: string }> {
33
+ export type TypeDisplay = {
34
+ icon: Component
35
+ label: string
36
+ }
37
+
38
+ export function buildTypeConfig(t: TranslationFunction): Record<ColumnType, TypeDisplay> {
19
39
  return {
20
40
  number: { icon: RiHashtag, label: t('Nombre') },
21
41
  categorical: { icon: RiPriceTag3Line, label: t('Catégoriel') },
@@ -25,6 +45,97 @@ export function buildTypeConfig(t: (s: string) => string): Record<ColumnType, {
25
45
  }
26
46
  }
27
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
+
57
+ // csv-detective formats that carry no semantic meaning beyond the generic
58
+ // display type already resolved by `ColumnType` — these fall back to
59
+ // `buildTypeConfig` (Texte / Nombre / Date / Booléen) in the header.
60
+ export const GENERIC_FORMATS = new Set(['string', 'int', 'float', 'date', 'bool', 'booleen'])
61
+
62
+ // Semantic types detected by csv-detective (see ../../../csv-detective/csv_detective/formats).
63
+ // The list is intentionally exhaustive, but unknown formats are tolerated:
64
+ // `getColumnDisplay` humanizes any format missing from this map.
65
+ export function buildFormatConfig(t: TranslationFunction): Record<string, TypeDisplay> {
66
+ return {
67
+ // Geo — territories & addresses
68
+ adresse: { icon: RiMapPin2Line, label: t('Adresse') },
69
+ commune: { icon: RiMapPin2Line, label: t('Commune') },
70
+ code_commune: { icon: RiMapPin2Line, label: t('Code INSEE commune') },
71
+ code_commune_insee: { icon: RiMapPin2Line, label: t('Code INSEE commune') },
72
+ departement: { icon: RiMapPin2Line, label: t('Département') },
73
+ code_departement: { icon: RiMapPin2Line, label: t('Code département') },
74
+ region: { icon: RiMapPin2Line, label: t('Région') },
75
+ code_region: { icon: RiMapPin2Line, label: t('Code région') },
76
+ code_epci: { icon: RiMapPin2Line, label: t('Code EPCI') },
77
+ code_postal: { icon: RiMapPin2Line, label: t('Code postal') },
78
+ insee_canton: { icon: RiMapPin2Line, label: t('Canton') },
79
+ code_fantoir: { icon: RiMapPin2Line, label: t('Code FANTOIR') },
80
+ id_rnb: { icon: RiMapPin2Line, label: t('Identifiant RNB') },
81
+ // Geo — countries
82
+ pays: { icon: RiGlobalLine, label: t('Pays') },
83
+ iso_country_code_alpha2: { icon: RiGlobalLine, label: t('Code pays (ISO α-2)') },
84
+ iso_country_code_alpha3: { icon: RiGlobalLine, label: t('Code pays (ISO α-3)') },
85
+ iso_country_code_numeric: { icon: RiGlobalLine, label: t('Code pays (ISO num.)') },
86
+ // Geo — coordinates
87
+ latitude_wgs: { icon: RiFocus3Line, label: t('Latitude') },
88
+ latitude_wgs_fr_metropole: { icon: RiFocus3Line, label: t('Latitude') },
89
+ longitude_wgs: { icon: RiFocus3Line, label: t('Longitude') },
90
+ longitude_wgs_fr_metropole: { icon: RiFocus3Line, label: t('Longitude') },
91
+ latitude_l93: { icon: RiFocus3Line, label: t('Latitude (Lambert 93)') },
92
+ longitude_l93: { icon: RiFocus3Line, label: t('Longitude (Lambert 93)') },
93
+ latlon_wgs: { icon: RiFocus3Line, label: t('Latitude / longitude') },
94
+ lonlat_wgs: { icon: RiFocus3Line, label: t('Longitude / latitude') },
95
+ // Identifiers
96
+ siren: { icon: RiFingerprintLine, label: t('SIREN') },
97
+ siret: { icon: RiFingerprintLine, label: t('SIRET') },
98
+ code_rna: { icon: RiFingerprintLine, label: t('Identifiant RNA') },
99
+ code_waldec: { icon: RiFingerprintLine, label: t('Identifiant WALDEC') },
100
+ code_import: { icon: RiFingerprintLine, label: t('Code Import') },
101
+ uai: { icon: RiFingerprintLine, label: t('UAI') },
102
+ insee_ape700: { icon: RiFingerprintLine, label: t('Code APE') },
103
+ code_csp_insee: { icon: RiFingerprintLine, label: t('Code CSP') },
104
+ uuid: { icon: RiFingerprintLine, label: t('UUID') },
105
+ mongo_object_id: { icon: RiFingerprintLine, label: t('Identifiant Mongo') },
106
+ // Contact
107
+ email: { icon: RiMailLine, label: t('Email') },
108
+ url: { icon: RiLinksLine, label: t('URL') },
109
+ tel_fr: { icon: RiPhoneLine, label: t('Téléphone') },
110
+ username: { icon: RiUserLine, label: t('Nom d\'utilisateur') },
111
+ // People
112
+ sexe: { icon: RiUserLine, label: t('Sexe') },
113
+ csp_insee: { icon: RiUserLine, label: t('Catégorie socio-pro.') },
114
+ // Quantities
115
+ money: { icon: RiMoneyEuroCircleLine, label: t('Montant') },
116
+ percent: { icon: RiPercentLine, label: t('Pourcentage') },
117
+ // Temporal
118
+ year: { icon: RiCalendarLine, label: t('Année') },
119
+ date_fr: { icon: RiCalendarLine, label: t('Date') },
120
+ jour_de_la_semaine: { icon: RiCalendarEventLine, label: t('Jour de la semaine') },
121
+ mois_de_lannee: { icon: RiCalendarEventLine, label: t('Mois de l\'année') },
122
+ datetime_naive: { icon: RiTimeLine, label: t('Date et heure') },
123
+ datetime_aware: { icon: RiTimeLine, label: t('Date et heure') },
124
+ datetime_rfc822: { icon: RiTimeLine, label: t('Date et heure') },
125
+ // Structured
126
+ json: { icon: RiBracesLine, label: t('JSON') },
127
+ geojson: { icon: RiBracesLine, label: t('GeoJSON') },
128
+ binary: { icon: RiCodeLine, label: t('Binaire') },
129
+ }
130
+ }
131
+
132
+ // Tolerant fallback for a semantic format we don't explicitly know about:
133
+ // "code_truc_machin" -> "Code truc machin".
134
+ export function humanizeFormat(format: string): string {
135
+ const spaced = format.replace(/_/g, ' ').trim()
136
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1)
137
+ }
138
+
28
139
  export function useFormatTabular() {
29
140
  const { locale } = useTranslation()
30
141
 
@@ -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>>