@datagouv/components-next 1.0.2-dev.68 → 1.0.2-dev.69
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-mCVEbSye.js → Datafair.client-B57v03ac.js} +1 -1
- package/dist/{JsonPreview.client-D2-QXKW9.js → JsonPreview.client-C7uJkiI6.js} +2 -2
- package/dist/{MapContainer.client-fG7SH8SY.js → MapContainer.client-D9AVgKoU.js} +2 -2
- package/dist/{PdfPreview.client-BD2LoeWd.js → PdfPreview.client-3_AtEyvC.js} +2 -2
- package/dist/{Pmtiles.client-BoISUK3N.js → Pmtiles.client-D00kMVdH.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-BRkoVZX6.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-NHqgUJAK.js} +1 -1
- package/dist/{XmlPreview.client-D4beM-9H.js → XmlPreview.client-Bn2kpzCg.js} +3 -3
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +166 -157
- package/dist/components.css +1 -1
- package/dist/{index-CHqTMS42.js → index-BPZOlCaf.js} +1 -1
- package/dist/{main-vXPsdhWv.js → main-By-J5lfU.js} +79299 -31033
- package/dist/{vue3-xml-viewer.common-S2fcy_RO.js → vue3-xml-viewer.common-D-uUQRA7.js} +1 -1
- package/package.json +2 -1
- package/src/components/Chart/ChartViewer.vue +226 -0
- package/src/components/Chart/ChartViewerWrapper.vue +170 -0
- package/src/components/Form/Listbox.vue +101 -0
- package/src/components/ResourceAccordion/Preview.vue +1 -1
- package/src/composables/useHasTabularData.ts +6 -0
- package/src/config.ts +1 -0
- package/src/functions/charts.ts +68 -0
- package/src/functions/tabularApi.ts +136 -7
- package/src/main.ts +27 -0
- package/src/types/visualizations.ts +89 -0
|
@@ -1,18 +1,147 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch'
|
|
2
2
|
import { useComponentsConfig, type PluginConfig } from '../config'
|
|
3
|
+
import type { GenericFilter } from '../types/visualizations'
|
|
3
4
|
import type { SortConfig } from '../components/TabularExplorer/types'
|
|
4
5
|
|
|
5
6
|
export type { SortConfig }
|
|
6
7
|
|
|
8
|
+
export type TabularDataResponse = {
|
|
9
|
+
data: Array<Record<string, unknown>>
|
|
10
|
+
links: {
|
|
11
|
+
profile: string
|
|
12
|
+
swagger: string
|
|
13
|
+
next: string
|
|
14
|
+
}
|
|
15
|
+
meta: { total: number }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type TabularAggregateType = 'avg' | 'sum' | 'count' | 'min' | 'max'
|
|
19
|
+
|
|
20
|
+
export type FetchTabularDataOptions = {
|
|
21
|
+
resourceId: string
|
|
22
|
+
page?: number
|
|
23
|
+
pageSize?: number
|
|
24
|
+
columns?: Array<string> | undefined
|
|
25
|
+
sort?: SortConfig
|
|
26
|
+
groupBy?: string | undefined
|
|
27
|
+
aggregation?: {
|
|
28
|
+
column: string
|
|
29
|
+
type: TabularAggregateType
|
|
30
|
+
} | undefined
|
|
31
|
+
filters?: GenericFilter | undefined
|
|
32
|
+
}
|
|
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
|
+
|
|
7
76
|
/**
|
|
8
|
-
* Call Tabular-api to get table content
|
|
77
|
+
* Call Tabular-api to get table content with options object
|
|
9
78
|
*/
|
|
10
|
-
export async function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
79
|
+
export async function fetchTabularData(config: PluginConfig, options: FetchTabularDataOptions): Promise<TabularDataResponse> {
|
|
80
|
+
const page = options.page ?? 1
|
|
81
|
+
const pageSize = options.pageSize ?? config.tabularApiPageSize ?? 15
|
|
82
|
+
let url = `${config.tabularApiUrl}/api/resources/${options.resourceId}/data/?page=${page}&page_size=${pageSize}`
|
|
83
|
+
if (options.columns) {
|
|
84
|
+
url += `&columns=${options.columns.map(col => encodeURIComponent(col)).join(',')}`
|
|
85
|
+
}
|
|
86
|
+
if (options.sort) {
|
|
87
|
+
url += `&${encodeURIComponent(options.sort.column)}__sort=${encodeURIComponent(options.sort.direction)}`
|
|
14
88
|
}
|
|
15
|
-
|
|
89
|
+
if (options.groupBy && options.aggregation?.type) {
|
|
90
|
+
url += `&${encodeURIComponent(options.groupBy)}__groupby&${encodeURIComponent(options.aggregation.column)}__${encodeURIComponent(options.aggregation.type)}`
|
|
91
|
+
}
|
|
92
|
+
if (options.filters) {
|
|
93
|
+
const filterQuery = buildFilterQuery(options.filters)
|
|
94
|
+
if (filterQuery) {
|
|
95
|
+
url += `&${filterQuery}`
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return await ofetch<TabularDataResponse>(url)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildFilterQuery(filters: GenericFilter): string {
|
|
102
|
+
const params: Array<string> = []
|
|
103
|
+
if ('filters' in filters) {
|
|
104
|
+
for (const filter of filters.filters) {
|
|
105
|
+
if ('filters' in filter) {
|
|
106
|
+
params.push(buildFilterQuery(filter))
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
if (filter.condition === 'is_null') {
|
|
110
|
+
params.push(`${encodeURIComponent(filter.column)}__isnull`)
|
|
111
|
+
}
|
|
112
|
+
else if (filter.condition === 'is_not_null') {
|
|
113
|
+
params.push(`${encodeURIComponent(filter.column)}__isnotnull`)
|
|
114
|
+
}
|
|
115
|
+
else if (filter.value !== null && filter.value !== undefined && filter.value !== '') {
|
|
116
|
+
params.push(`${encodeURIComponent(filter.column)}__${encodeURIComponent(filter.condition)}=${encodeURIComponent(filter.value)}`)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const filter = filters
|
|
123
|
+
if (filter.condition === 'is_null') {
|
|
124
|
+
params.push(`${encodeURIComponent(filter.column)}__isnull`)
|
|
125
|
+
}
|
|
126
|
+
else if (filter.condition === 'is_not_null') {
|
|
127
|
+
params.push(`${encodeURIComponent(filter.column)}__isnotnull`)
|
|
128
|
+
}
|
|
129
|
+
else if (filter.value !== null && filter.value !== undefined && filter.value !== '') {
|
|
130
|
+
params.push(`${encodeURIComponent(filter.column)}__${encodeURIComponent(filter.condition)}=${encodeURIComponent(filter.value)}`)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return params.join('&')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Call Tabular-api to get table content
|
|
138
|
+
*/
|
|
139
|
+
export async function getData(config: PluginConfig, id: string, page: number, sortConfig?: SortConfig | null): Promise<TabularDataResponse> {
|
|
140
|
+
return fetchTabularData(config, {
|
|
141
|
+
resourceId: id,
|
|
142
|
+
page,
|
|
143
|
+
sort: sortConfig ?? undefined,
|
|
144
|
+
})
|
|
16
145
|
}
|
|
17
146
|
|
|
18
147
|
/**
|
|
@@ -20,5 +149,5 @@ export async function getData(config: PluginConfig, id: string, page: number, so
|
|
|
20
149
|
*/
|
|
21
150
|
export function useGetProfile() {
|
|
22
151
|
const config = useComponentsConfig()
|
|
23
|
-
return (id: string) => ofetch(`${config.tabularApiUrl}/api/resources/${id}/profile/`)
|
|
152
|
+
return (id: string) => ofetch<TabularProfileResponse>(`${config.tabularApiUrl}/api/resources/${id}/profile/`)
|
|
24
153
|
}
|
package/src/main.ts
CHANGED
|
@@ -23,6 +23,7 @@ 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
27
|
import type { GlobalSearchConfig, SearchType, SearchTypeConfig, SortOption, HiddenFilter, BuiltInFilterKey, DatasetSearchConfig, DatasetSearchFilters, DataserviceSearchConfig, DataserviceSearchFilters, ReuseSearchConfig, ReuseSearchFilters, OrganizationSearchConfig, OrganizationSearchFilters, TopicSearchConfig, TopicSearchFilters } from './types/search'
|
|
27
28
|
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
28
29
|
import { useSearchFilter } from './composables/useSearchFilter'
|
|
@@ -82,6 +83,8 @@ import ReuseDetails from './components/ReuseDetails.vue'
|
|
|
82
83
|
import SchemaCard from './components/SchemaCard.vue'
|
|
83
84
|
import SimpleBanner from './components/SimpleBanner.vue'
|
|
84
85
|
import SmallChart from './components/SmallChart.vue'
|
|
86
|
+
import ChartViewer from './components/Chart/ChartViewer.vue'
|
|
87
|
+
import ChartViewerWrapper from './components/Chart/ChartViewerWrapper.vue'
|
|
85
88
|
import StatBox from './components/StatBox.vue'
|
|
86
89
|
import Tab from './components/Tabs/Tab.vue'
|
|
87
90
|
import TabGroup from './components/Tabs/TabGroup.vue'
|
|
@@ -96,6 +99,7 @@ import GlobalSearch from './components/Search/GlobalSearch.vue'
|
|
|
96
99
|
import SearchInput from './components/Search/SearchInput.vue'
|
|
97
100
|
import SearchableSelect from './components/Form/SearchableSelect.vue'
|
|
98
101
|
import SelectGroup from './components/Form/SelectGroup.vue'
|
|
102
|
+
import Listbox from './components/Form/Listbox.vue'
|
|
99
103
|
import InfiniteLoader from './components/InfiniteLoader.vue'
|
|
100
104
|
import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
|
|
101
105
|
import type { UseFetchFunction } from './functions/api.types'
|
|
@@ -104,6 +108,7 @@ import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
|
|
|
104
108
|
export { Toaster, toast } from 'vue-sonner'
|
|
105
109
|
|
|
106
110
|
export * from './composables/useActiveDescendant'
|
|
111
|
+
export * from './composables/useDebouncedRef'
|
|
107
112
|
export * from './composables/useMetrics'
|
|
108
113
|
export * from './composables/useReuseType'
|
|
109
114
|
export * from './composables/useTranslation'
|
|
@@ -125,6 +130,8 @@ export * from './functions/reuses'
|
|
|
125
130
|
export * from './functions/schemas'
|
|
126
131
|
export * from './functions/tabular'
|
|
127
132
|
export * from './functions/users'
|
|
133
|
+
export * from './functions/tabularApi'
|
|
134
|
+
export * from './functions/charts'
|
|
128
135
|
export * from './types/access_types'
|
|
129
136
|
|
|
130
137
|
export type {
|
|
@@ -235,6 +242,23 @@ export type {
|
|
|
235
242
|
ValidataError,
|
|
236
243
|
Weight,
|
|
237
244
|
WellType,
|
|
245
|
+
Chart,
|
|
246
|
+
ChartForm,
|
|
247
|
+
ChartForApi,
|
|
248
|
+
FilterCondition,
|
|
249
|
+
Filter,
|
|
250
|
+
AndFilters,
|
|
251
|
+
GenericFilter,
|
|
252
|
+
XAxisType,
|
|
253
|
+
XAxisSortBy,
|
|
254
|
+
SortDirection,
|
|
255
|
+
XAxis,
|
|
256
|
+
XAxisForm,
|
|
257
|
+
UnitPosition,
|
|
258
|
+
YAxis,
|
|
259
|
+
DataSeriesType,
|
|
260
|
+
DataSeries,
|
|
261
|
+
DataSeriesForm,
|
|
238
262
|
}
|
|
239
263
|
|
|
240
264
|
export {
|
|
@@ -321,6 +345,8 @@ export {
|
|
|
321
345
|
SchemaCard,
|
|
322
346
|
SimpleBanner,
|
|
323
347
|
SmallChart,
|
|
348
|
+
ChartViewer,
|
|
349
|
+
ChartViewerWrapper,
|
|
324
350
|
StatBox,
|
|
325
351
|
OpenApiViewer,
|
|
326
352
|
Tab,
|
|
@@ -337,6 +363,7 @@ export {
|
|
|
337
363
|
SearchInput,
|
|
338
364
|
SearchableSelect,
|
|
339
365
|
SelectGroup,
|
|
366
|
+
Listbox,
|
|
340
367
|
InfiniteLoader,
|
|
341
368
|
TabularExplorer,
|
|
342
369
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { TabularAggregateType } from '../functions/tabularApi'
|
|
2
|
+
import type { Owned, OwnedWithId } from './owned'
|
|
3
|
+
|
|
4
|
+
export type FilterCondition = 'exact' | 'differs' | 'is_null' | 'is_not_null' | 'greater' | 'less' | 'strictly_greater' | 'strictly_less'
|
|
5
|
+
export type Filter = {
|
|
6
|
+
_cls: 'Filter'
|
|
7
|
+
column: string
|
|
8
|
+
condition: FilterCondition
|
|
9
|
+
value: string | null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type AndFilters = {
|
|
13
|
+
_cls: 'AndFilters'
|
|
14
|
+
filters: Array<Filter | AndFilters>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type GenericFilter = Filter | AndFilters
|
|
18
|
+
|
|
19
|
+
export type XAxisType = 'discrete' | 'continuous'
|
|
20
|
+
|
|
21
|
+
export type XAxisSortBy = 'axis_x' | 'axis_y'
|
|
22
|
+
|
|
23
|
+
export type SortDirection = 'asc' | 'desc'
|
|
24
|
+
|
|
25
|
+
export type XAxis = {
|
|
26
|
+
column_x: string
|
|
27
|
+
sort_x_by: XAxisSortBy | null
|
|
28
|
+
sort_x_direction: SortDirection | null
|
|
29
|
+
type: XAxisType
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type CombinedSort = '' | 'axis_x-asc' | 'axis_x-desc' | 'axis_y-asc' | 'axis_y-desc'
|
|
33
|
+
|
|
34
|
+
export type XAxisForm = Omit<XAxis, 'sort_x_by' | 'sort_x_direction'> & { sort_combined: CombinedSort }
|
|
35
|
+
|
|
36
|
+
export type UnitPosition = 'prefix' | 'suffix'
|
|
37
|
+
|
|
38
|
+
export type YAxis = {
|
|
39
|
+
min: number | null
|
|
40
|
+
max: number | null
|
|
41
|
+
label: string | null
|
|
42
|
+
unit: string | null
|
|
43
|
+
unit_position: UnitPosition | null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type DataSeriesType = 'line' | 'histogram'
|
|
47
|
+
|
|
48
|
+
export type DataSeries = {
|
|
49
|
+
type: DataSeriesType
|
|
50
|
+
column_y: string
|
|
51
|
+
aggregate_y: TabularAggregateType | null
|
|
52
|
+
resource_id: string
|
|
53
|
+
column_x_name_override: string | null
|
|
54
|
+
filters: GenericFilter | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Type for form where aggregate_y can be empty string for select binding
|
|
58
|
+
export type DataSeriesForm = Omit<DataSeries, 'aggregate_y'> & { aggregate_y: TabularAggregateType | '' | null }
|
|
59
|
+
|
|
60
|
+
export type Chart = Owned & {
|
|
61
|
+
id: string
|
|
62
|
+
title: string
|
|
63
|
+
slug: string
|
|
64
|
+
description: string
|
|
65
|
+
private: boolean
|
|
66
|
+
created_at: string
|
|
67
|
+
last_modified: string
|
|
68
|
+
deleted_at: string | null
|
|
69
|
+
uri: string
|
|
70
|
+
page: string
|
|
71
|
+
x_axis: XAxis
|
|
72
|
+
y_axis: YAxis
|
|
73
|
+
series: Array<DataSeries>
|
|
74
|
+
extras: Record<string, unknown>
|
|
75
|
+
permissions: { delete: boolean, edit: boolean, read: boolean }
|
|
76
|
+
metrics: {
|
|
77
|
+
views: number
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ChartForApi = OwnedWithId & Pick<Chart, 'title' | 'description' | 'private' | 'x_axis' | 'y_axis' | 'series' | 'extras'>
|
|
82
|
+
|
|
83
|
+
export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organization'> & {
|
|
84
|
+
owned: OwnedWithId
|
|
85
|
+
x_axis: XAxisForm
|
|
86
|
+
series: Array<DataSeriesForm>
|
|
87
|
+
chart_type?: DataSeriesType | null
|
|
88
|
+
filter: GenericFilter | null
|
|
89
|
+
}
|