@datagouv/components-next 1.0.2-dev.53 → 1.0.2-dev.54
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/assets/main.css +4 -0
- package/dist/{Datafair.client-hLoIoNbP.js → Datafair.client-qm_JoZUL.js} +1 -1
- package/dist/{JsonPreview.client-BUCeeFKz.js → JsonPreview.client-BpovqdDN.js} +2 -2
- package/dist/{MapContainer.client-DrQRSrq_.js → MapContainer.client-6Y5RJxtw.js} +2 -2
- package/dist/{PdfPreview.client-vQ4bfJx3.js → PdfPreview.client-Drv5EwJe.js} +2 -2
- package/dist/{Pmtiles.client-DWtu_UNl.js → Pmtiles.client-B3dUb4iS.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-4Ufr2Kmw.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BmRAxeK4.js} +1 -1
- package/dist/{XmlPreview.client-CEEHnAFF.js → XmlPreview.client-CXF1N-AI.js} +3 -3
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +136 -128
- package/dist/components.css +1 -1
- package/dist/{index-CsOZmih1.js → index-lCAbcwQm.js} +1 -1
- package/dist/{main-7DRSPyNj.js → main-5ZJvZtsQ.js} +22490 -20505
- package/dist/{vue3-xml-viewer.common-DOIGuzsk.js → vue3-xml-viewer.common-X_gxbf2s.js} +1 -1
- package/package.json +1 -1
- package/src/components/InfiniteLoader.vue +53 -0
- package/src/components/ResourceAccordion/Preview.vue +10 -10
- package/src/components/ResourceAccordion/ResourceAccordion.vue +1 -1
- package/src/components/ResourceExplorer/ResourceExplorer.vue +60 -3
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +4 -3
- package/src/components/Search/GlobalSearch.vue +45 -4
- package/src/components/TabularExplorer/TabularCell.vue +51 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +870 -0
- package/src/components/TabularExplorer/TabularFilterContent.vue +351 -0
- package/src/components/TabularExplorer/TabularFilterPopover.vue +111 -0
- package/src/components/TabularExplorer/types.ts +83 -0
- package/src/composables/useSearchFilter.ts +90 -0
- package/src/composables/useStableQueryParams.ts +28 -3
- package/src/functions/api.ts +34 -33
- package/src/functions/api.types.ts +1 -0
- package/src/functions/tabular.ts +60 -0
- package/src/functions/tabularApi.ts +4 -6
- package/src/main.ts +9 -0
package/src/functions/api.ts
CHANGED
|
@@ -24,6 +24,7 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
24
24
|
return await config.customUseFetch(url, options)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const isRaw = options?.raw
|
|
27
28
|
const data: Ref<DataT | null> = ref(null)
|
|
28
29
|
const error: Ref<ErrorT | null> = ref(null)
|
|
29
30
|
const status = ref<AsyncDataRequestStatus>('idle')
|
|
@@ -35,37 +36,39 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
35
36
|
const query = deepToValue(options?.query)
|
|
36
37
|
status.value = 'pending'
|
|
37
38
|
try {
|
|
38
|
-
data.value =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
config.onRequest
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
data.value = isRaw
|
|
40
|
+
? await ofetch<DataT | null>(urlValue, { params: params ?? query })
|
|
41
|
+
: await ofetch<DataT | null>(urlValue, {
|
|
42
|
+
baseURL: config.apiBase,
|
|
43
|
+
params: params ?? query,
|
|
44
|
+
onRequest(param) {
|
|
45
|
+
if (config.onRequest) {
|
|
46
|
+
if (Array.isArray(config.onRequest)) {
|
|
47
|
+
config.onRequest.forEach(r => r(param))
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
config.onRequest(param)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const { options } = param
|
|
54
|
+
options.headers.set('Content-Type', 'application/json')
|
|
55
|
+
options.headers.set('Accept', 'application/json')
|
|
56
|
+
options.credentials = 'include'
|
|
57
|
+
if (config.devApiKey) {
|
|
58
|
+
options.headers.set('X-API-KEY', config.devApiKey)
|
|
59
|
+
}
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
if (locale) {
|
|
62
|
+
if (!options.params) {
|
|
63
|
+
options.params = {}
|
|
64
|
+
}
|
|
65
|
+
options.params['lang'] = locale
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
onRequestError: config.onRequestError,
|
|
69
|
+
onResponse: config.onResponse,
|
|
70
|
+
onResponseError: config.onResponseError,
|
|
71
|
+
})
|
|
69
72
|
status.value = 'success'
|
|
70
73
|
}
|
|
71
74
|
catch (e) {
|
|
@@ -90,9 +93,7 @@ export async function useFetch<DataT, ErrorT = never>(
|
|
|
90
93
|
|
|
91
94
|
return {
|
|
92
95
|
data,
|
|
93
|
-
refresh:
|
|
94
|
-
execute()
|
|
95
|
-
},
|
|
96
|
+
refresh: () => execute(),
|
|
96
97
|
execute,
|
|
97
98
|
clear: () => {
|
|
98
99
|
data.value = null
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Component } from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
RiHashtag,
|
|
4
|
+
RiPriceTag3Line,
|
|
5
|
+
RiText,
|
|
6
|
+
RiCalendarLine,
|
|
7
|
+
RiCheckboxLine,
|
|
8
|
+
} from '@remixicon/vue'
|
|
9
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
10
|
+
import type { ColumnFilters, ColumnType } from '../components/TabularExplorer/types'
|
|
11
|
+
|
|
12
|
+
export function hasFilterForColumn(filters: Record<string, ColumnFilters>, column: string): boolean {
|
|
13
|
+
const f = filters[column]
|
|
14
|
+
if (!f) return false
|
|
15
|
+
return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function buildTypeConfig(t: (s: string) => string): Record<ColumnType, { icon: Component, label: string }> {
|
|
19
|
+
return {
|
|
20
|
+
number: { icon: RiHashtag, label: t('Nombre') },
|
|
21
|
+
categorical: { icon: RiPriceTag3Line, label: t('Catégoriel') },
|
|
22
|
+
text: { icon: RiText, label: t('Texte') },
|
|
23
|
+
date: { icon: RiCalendarLine, label: t('Date') },
|
|
24
|
+
boolean: { icon: RiCheckboxLine, label: t('Booléen') },
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useFormatTabular() {
|
|
29
|
+
const { locale } = useTranslation()
|
|
30
|
+
|
|
31
|
+
function formatNumber(value: unknown): string {
|
|
32
|
+
const num = Number(value)
|
|
33
|
+
if (Number.isNaN(num)) return String(value)
|
|
34
|
+
return num.toLocaleString(locale)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function formatCellDate(value: unknown): string {
|
|
38
|
+
if (value == null || value === '') return '–'
|
|
39
|
+
const d = new Date(String(value))
|
|
40
|
+
if (Number.isNaN(d.getTime())) return String(value)
|
|
41
|
+
return new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(d)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { formatNumber, formatCellDate }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const TRUTHY_VALUES = ['true', '1', 'oui', 'yes']
|
|
48
|
+
const FALSY_VALUES = ['false', '0', 'non', 'no']
|
|
49
|
+
|
|
50
|
+
export function isTruthy(value: unknown): boolean {
|
|
51
|
+
if (typeof value === 'boolean') return value
|
|
52
|
+
if (typeof value === 'string') return TRUTHY_VALUES.includes(value.toLowerCase())
|
|
53
|
+
return Boolean(value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isFalsy(value: unknown): boolean {
|
|
57
|
+
if (typeof value === 'boolean') return !value
|
|
58
|
+
if (typeof value === 'string') return FALSY_VALUES.includes(value.toLowerCase())
|
|
59
|
+
return !value
|
|
60
|
+
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch'
|
|
2
2
|
import { useComponentsConfig, type PluginConfig } from '../config'
|
|
3
|
+
import type { SortConfig } from '../components/TabularExplorer/types'
|
|
3
4
|
|
|
4
|
-
export type SortConfig
|
|
5
|
-
column: string
|
|
6
|
-
type: string
|
|
7
|
-
} | null
|
|
5
|
+
export type { SortConfig }
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Call Tabular-api to get table content
|
|
11
9
|
*/
|
|
12
|
-
export async function getData(config: PluginConfig, id: string, page: number, sortConfig?: SortConfig) {
|
|
10
|
+
export async function getData(config: PluginConfig, id: string, page: number, sortConfig?: SortConfig | null) {
|
|
13
11
|
let url = `${config.tabularApiUrl}/api/resources/${id}/data/?page=${page}&page_size=${config.tabularApiPageSize || 15}`
|
|
14
12
|
if (sortConfig) {
|
|
15
|
-
url = url + `&${sortConfig.column}__sort=${sortConfig.
|
|
13
|
+
url = url + `&${sortConfig.column}__sort=${sortConfig.direction}`
|
|
16
14
|
}
|
|
17
15
|
return await ofetch(url)
|
|
18
16
|
}
|
package/src/main.ts
CHANGED
|
@@ -25,6 +25,8 @@ import type { User, UserReference } from './types/users'
|
|
|
25
25
|
import type { Report, ReportSubject, ReportReason } from './types/reports'
|
|
26
26
|
import type { GlobalSearchConfig, SearchType, SortOption } from './types/search'
|
|
27
27
|
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
28
|
+
import { useSearchFilter } from './composables/useSearchFilter'
|
|
29
|
+
import type { UseSearchFilterOptions } from './composables/useSearchFilter'
|
|
28
30
|
|
|
29
31
|
import ActivityList from './components/ActivityList/ActivityList.vue'
|
|
30
32
|
import UserActivityList from './components/ActivityList/UserActivityList.vue'
|
|
@@ -94,6 +96,8 @@ import GlobalSearch from './components/Search/GlobalSearch.vue'
|
|
|
94
96
|
import SearchInput from './components/Search/SearchInput.vue'
|
|
95
97
|
import SearchableSelect from './components/Form/SearchableSelect.vue'
|
|
96
98
|
import SelectGroup from './components/Form/SelectGroup.vue'
|
|
99
|
+
import InfiniteLoader from './components/InfiniteLoader.vue'
|
|
100
|
+
import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
|
|
97
101
|
import type { UseFetchFunction } from './functions/api.types'
|
|
98
102
|
import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
|
|
99
103
|
|
|
@@ -119,6 +123,7 @@ export * from './functions/owned'
|
|
|
119
123
|
export * from './functions/resources'
|
|
120
124
|
export * from './functions/reuses'
|
|
121
125
|
export * from './functions/schemas'
|
|
126
|
+
export * from './functions/tabular'
|
|
122
127
|
export * from './functions/users'
|
|
123
128
|
export * from './types/access_types'
|
|
124
129
|
|
|
@@ -126,6 +131,7 @@ export type {
|
|
|
126
131
|
GlobalSearchConfig,
|
|
127
132
|
SearchType,
|
|
128
133
|
SortOption,
|
|
134
|
+
UseSearchFilterOptions,
|
|
129
135
|
UseFetchFunction,
|
|
130
136
|
AccessType,
|
|
131
137
|
AccessAudience,
|
|
@@ -229,6 +235,7 @@ export {
|
|
|
229
235
|
defaultDataserviceSortOptions,
|
|
230
236
|
defaultReuseSortOptions,
|
|
231
237
|
defaultOrganizationSortOptions,
|
|
238
|
+
useSearchFilter,
|
|
232
239
|
}
|
|
233
240
|
|
|
234
241
|
// Vue Plugin
|
|
@@ -317,4 +324,6 @@ export {
|
|
|
317
324
|
SearchInput,
|
|
318
325
|
SearchableSelect,
|
|
319
326
|
SelectGroup,
|
|
327
|
+
InfiniteLoader,
|
|
328
|
+
TabularExplorer,
|
|
320
329
|
}
|