@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.
Files changed (35) hide show
  1. package/assets/main.css +4 -0
  2. package/dist/{Datafair.client-hLoIoNbP.js → Datafair.client-qm_JoZUL.js} +1 -1
  3. package/dist/{JsonPreview.client-BUCeeFKz.js → JsonPreview.client-BpovqdDN.js} +2 -2
  4. package/dist/{MapContainer.client-DrQRSrq_.js → MapContainer.client-6Y5RJxtw.js} +2 -2
  5. package/dist/{PdfPreview.client-vQ4bfJx3.js → PdfPreview.client-Drv5EwJe.js} +2 -2
  6. package/dist/{Pmtiles.client-DWtu_UNl.js → Pmtiles.client-B3dUb4iS.js} +1 -1
  7. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-4Ufr2Kmw.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BmRAxeK4.js} +1 -1
  8. package/dist/{XmlPreview.client-CEEHnAFF.js → XmlPreview.client-CXF1N-AI.js} +3 -3
  9. package/dist/components-next.css +1 -1
  10. package/dist/components-next.js +136 -128
  11. package/dist/components.css +1 -1
  12. package/dist/{index-CsOZmih1.js → index-lCAbcwQm.js} +1 -1
  13. package/dist/{main-7DRSPyNj.js → main-5ZJvZtsQ.js} +22490 -20505
  14. package/dist/{vue3-xml-viewer.common-DOIGuzsk.js → vue3-xml-viewer.common-X_gxbf2s.js} +1 -1
  15. package/package.json +1 -1
  16. package/src/components/InfiniteLoader.vue +53 -0
  17. package/src/components/ResourceAccordion/Preview.vue +10 -10
  18. package/src/components/ResourceAccordion/ResourceAccordion.vue +1 -1
  19. package/src/components/ResourceExplorer/ResourceExplorer.vue +60 -3
  20. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
  21. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +4 -3
  22. package/src/components/Search/GlobalSearch.vue +45 -4
  23. package/src/components/TabularExplorer/TabularCell.vue +51 -0
  24. package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
  25. package/src/components/TabularExplorer/TabularExplorer.vue +870 -0
  26. package/src/components/TabularExplorer/TabularFilterContent.vue +351 -0
  27. package/src/components/TabularExplorer/TabularFilterPopover.vue +111 -0
  28. package/src/components/TabularExplorer/types.ts +83 -0
  29. package/src/composables/useSearchFilter.ts +90 -0
  30. package/src/composables/useStableQueryParams.ts +28 -3
  31. package/src/functions/api.ts +34 -33
  32. package/src/functions/api.types.ts +1 -0
  33. package/src/functions/tabular.ts +60 -0
  34. package/src/functions/tabularApi.ts +4 -6
  35. package/src/main.ts +9 -0
@@ -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 = await ofetch<DataT | null>(urlValue, {
39
- baseURL: config.apiBase,
40
- params: params ?? query,
41
- onRequest(param) {
42
- if (config.onRequest) {
43
- if (Array.isArray(config.onRequest)) {
44
- config.onRequest.forEach(r => r(param))
45
- }
46
- else {
47
- config.onRequest(param)
48
- }
49
- }
50
- const { options } = param
51
- options.headers.set('Content-Type', 'application/json')
52
- options.headers.set('Accept', 'application/json')
53
- options.credentials = 'include'
54
- if (config.devApiKey) {
55
- options.headers.set('X-API-KEY', config.devApiKey)
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
- if (locale) {
59
- if (!options.params) {
60
- options.params = {}
61
- }
62
- options.params['lang'] = locale
63
- }
64
- },
65
- onRequestError: config.onRequestError,
66
- onResponse: config.onResponse,
67
- onResponseError: config.onResponseError,
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: async () => {
94
- execute()
95
- },
96
+ refresh: () => execute(),
96
97
  execute,
97
98
  clear: () => {
98
99
  data.value = null
@@ -20,6 +20,7 @@ export type UseFetchOptions<DataT> = {
20
20
  transform?: (input: DataT) => DataT | Promise<DataT>
21
21
  pick?: string[]
22
22
  watch?: WatchSource[] | false
23
+ raw?: boolean
23
24
  }
24
25
 
25
26
  export type AsyncData<DataT, ErrorT> = {
@@ -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.type}`
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
  }