@datagouv/components-next 1.3.0 → 1.4.0

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 (131) hide show
  1. package/dist/{Control-b-43UT2B.js → Control-B9WQxlpJ.js} +10 -10
  2. package/dist/{Datafair.client-BrjISlaZ.js → Datafair.client-D_6yzJUG.js} +9 -9
  3. package/dist/{Event-py_AAwJY.js → Event-iXDrp-fy.js} +15 -15
  4. package/dist/{Image-BHQYZWzH.js → Image-mNMBOofs.js} +22 -22
  5. package/dist/ImagePreview.client-B0iPhFm3.js +36 -0
  6. package/dist/{JsonPreview.client-DivFAnbN.js → JsonPreview.client-DSl1kiwC.js} +2 -2
  7. package/dist/{Map-CtP7leHl.js → Map-BfqKMw0S.js} +165 -165
  8. package/dist/{MapContainer.client-Cq8tNLZZ.js → MapContainer.client-BSfpk_rT.js} +17 -17
  9. package/dist/{OSM-gdDSIsDA.js → OSM-CcrUhItr.js} +1 -1
  10. package/dist/{PdfPreview.client-BNBgLsK2.js → PdfPreview.client-BANFeM6K.js} +438 -427
  11. package/dist/{Pmtiles.client-CQi5Rw8W.js → Pmtiles.client-DH9ZrsZR.js} +6177 -5967
  12. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-I8EZCgzp.js +60 -0
  13. package/dist/{ScaleLine-hG-FhNqy.js → ScaleLine-VGQ7nkMS.js} +2 -2
  14. package/dist/{Tile-D6rFonpT.js → Tile-CSpn0Ca8.js} +47 -47
  15. package/dist/{TileImage-cfrEgz5y.js → TileImage-CpbaEFwd.js} +44 -44
  16. package/dist/{View-vp7vDb9q.js → View-BYBpt-AU.js} +58 -58
  17. package/dist/{XmlPreview.client-XCsNvnsZ.js → XmlPreview.client-KCB5mwVf.js} +3 -3
  18. package/dist/{common-C8efyyuc.js → common-BoeTUnDZ.js} +58 -58
  19. package/dist/components-next.css +1 -1
  20. package/dist/components-next.js +199 -172
  21. package/dist/components.css +1 -1
  22. package/dist/{index-CXUamc8Z.js → index-DHWzX5vK.js} +4668 -4466
  23. package/dist/{leaflet-src-BRKv9Ksv.js → leaflet-src-pVQfonBI.js} +1 -1
  24. package/dist/{main-DKu5SOAl.js → main-BDcYkhOc.js} +41684 -33432
  25. package/dist/{proj-CsjVeojN.js → proj-DxGbobp7.js} +110 -110
  26. package/dist/{tilecoord-CPcQJnrF.js → tilecoord-DvX7WWiA.js} +94 -94
  27. package/dist/{vue3-xml-viewer.common-BIaEIFYG.js → vue3-xml-viewer.common-Bdcn54ST.js} +1 -1
  28. package/package.json +28 -27
  29. package/src/components/ActivityList/ActivityList.vue +21 -12
  30. package/src/components/AppLink.vue +3 -0
  31. package/src/components/BannerAction.vue +6 -2
  32. package/src/components/Chart/ChartViewer.vue +111 -17
  33. package/src/components/Chart/ChartViewerWrapper.vue +28 -16
  34. package/src/components/ChartCard.vue +112 -0
  35. package/src/components/CopyButton.vue +6 -2
  36. package/src/components/DataserviceCard.vue +23 -6
  37. package/src/components/DataserviceQuality.vue +82 -0
  38. package/src/components/DataserviceQualityInline.vue +31 -0
  39. package/src/components/DataserviceQualityTooltipContent.vue +79 -0
  40. package/src/components/DatasetCard.vue +17 -6
  41. package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -4
  42. package/src/components/DatasetQuality.vue +11 -11
  43. package/src/components/DatasetQualityInline.vue +2 -2
  44. package/src/components/DatasetQualityTooltipContent.vue +1 -1
  45. package/src/components/DiscussionMessageCard.vue +14 -15
  46. package/src/components/Form/SchemaSelect.vue +2 -0
  47. package/src/components/FormattedDate.vue +69 -0
  48. package/src/components/LoadingBlock.vue +4 -1
  49. package/src/components/ObjectCard.vue +4 -1
  50. package/src/components/ObjectCardOwner.vue +13 -1
  51. package/src/components/Pagination.vue +18 -58
  52. package/src/components/Placeholder.vue +3 -2
  53. package/src/components/PostCard.vue +13 -15
  54. package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
  55. package/src/components/ResourceAccordion/Downloads.vue +19 -7
  56. package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
  57. package/src/components/ResourceAccordion/MapContainer.client.vue +1 -8
  58. package/src/components/ResourceAccordion/Metadata.vue +21 -5
  59. package/src/components/ResourceAccordion/PdfPreview.client.vue +36 -12
  60. package/src/components/ResourceAccordion/PdfSkeleton.vue +44 -0
  61. package/src/components/ResourceAccordion/Pmtiles.client.vue +27 -18
  62. package/src/components/ResourceAccordion/Preview.vue +8 -4
  63. package/src/components/ResourceAccordion/PreviewWrapper.vue +17 -10
  64. package/src/components/ResourceAccordion/ResourceAccordion.vue +29 -9
  65. package/src/components/ResourceExplorer/ResourceExplorer.vue +105 -209
  66. package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +79 -0
  67. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +104 -71
  68. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +136 -183
  69. package/src/components/ResourceExplorer/ResourceMainAction.vue +240 -0
  70. package/src/components/ResourceExplorer/ResourceSelector.vue +24 -86
  71. package/src/components/ResourceExplorer/ResourceViewerHeader.vue +124 -0
  72. package/src/components/ResourceExplorer/ResourceViewerSkeleton.vue +96 -0
  73. package/src/components/ResourceListItem.vue +168 -0
  74. package/src/components/ReuseCard.vue +18 -6
  75. package/src/components/ReuseDetails.vue +2 -2
  76. package/src/components/ReuseHorizontalCard.vue +4 -3
  77. package/src/components/SchemaCard.vue +10 -1
  78. package/src/components/Search/Filter/AccessTypeFilter.vue +2 -2
  79. package/src/components/Search/GlobalSearch.vue +12 -8
  80. package/src/components/Search/SearchInput.vue +1 -1
  81. package/src/components/Search/Sidemenu.vue +4 -3
  82. package/src/components/SmallChart.vue +11 -10
  83. package/src/components/StatBox.vue +13 -5
  84. package/src/components/TabularExplorer/TabularActiveFilters.vue +79 -0
  85. package/src/components/TabularExplorer/TabularCell.vue +7 -8
  86. package/src/components/TabularExplorer/TabularCellPopover.vue +19 -3
  87. package/src/components/TabularExplorer/TabularColumnsMenu.vue +112 -0
  88. package/src/components/TabularExplorer/TabularDateField.vue +41 -0
  89. package/src/components/TabularExplorer/TabularDateFilter.vue +403 -0
  90. package/src/components/TabularExplorer/TabularExplorer.vue +122 -913
  91. package/src/components/TabularExplorer/TabularFilterContent.vue +33 -25
  92. package/src/components/TabularExplorer/TabularFilterPopover.vue +7 -7
  93. package/src/components/TabularExplorer/TabularMobileFilterButton.vue +21 -0
  94. package/src/components/TabularExplorer/TabularMobileFilters.vue +150 -0
  95. package/src/components/TabularExplorer/TabularRowsInfo.vue +31 -0
  96. package/src/components/TabularExplorer/TabularSkeleton.vue +92 -0
  97. package/src/components/TabularExplorer/TabularTable.vue +484 -0
  98. package/src/components/TabularExplorer/TabularToolbar.vue +25 -0
  99. package/src/components/TabularExplorer/types.ts +32 -20
  100. package/src/components/TabularExplorer/useColumnMetadata.ts +98 -0
  101. package/src/components/TabularExplorer/useTabularContext.ts +82 -0
  102. package/src/components/TopicCard.vue +15 -14
  103. package/src/composables/useActiveDescendant.ts +5 -0
  104. package/src/composables/useDatasetResources.ts +164 -0
  105. package/src/composables/useHasTabularData.ts +2 -1
  106. package/src/composables/useResizable.ts +46 -0
  107. package/src/composables/useResourceCapabilities.ts +47 -39
  108. package/src/composables/useTranslation.ts +24 -9
  109. package/src/config.ts +1 -0
  110. package/src/functions/charts.ts +32 -1
  111. package/src/functions/dates.ts +26 -7
  112. package/src/functions/helpers.ts +15 -0
  113. package/src/functions/metrics.ts +57 -56
  114. package/src/functions/owned.ts +21 -0
  115. package/src/functions/paginate.ts +46 -0
  116. package/src/functions/resourceCapabilities.ts +34 -0
  117. package/src/functions/resources.ts +83 -0
  118. package/src/functions/schemas.ts +27 -0
  119. package/src/functions/scroll.ts +20 -0
  120. package/src/functions/tabular.ts +119 -4
  121. package/src/functions/tabularApi.ts +1 -43
  122. package/src/main.ts +32 -6
  123. package/src/types/dataservices.ts +15 -0
  124. package/src/types/organizations.ts +10 -0
  125. package/src/types/reuses.ts +12 -1
  126. package/src/types/search.ts +2 -2
  127. package/src/types/visualizations.ts +5 -0
  128. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-C3dDzrIr.js +0 -61
  129. /package/src/components/{DatasetQualityItem.vue → QualityItem.vue} +0 -0
  130. /package/src/components/{DatasetQualityItemWarning.vue → QualityItemWarning.vue} +0 -0
  131. /package/src/components/{DatasetQualityScore.vue → QualityScore.vue} +0 -0
@@ -1,4 +1,5 @@
1
1
  import type { Component } from 'vue'
2
+ import { parseDate, type CalendarDate } from '@internationalized/date'
2
3
  import {
3
4
  RiHashtag,
4
5
  RiPriceTag3Line,
@@ -22,12 +23,74 @@ import {
22
23
  } from '@remixicon/vue'
23
24
  import { useTranslation } from '../composables/useTranslation'
24
25
  import type { TranslationFunction } from '../composables/useTranslation'
25
- import type { ColumnFilters, ColumnType } from '../components/TabularExplorer/types'
26
+ import type { ColumnFilters, ColumnType, DateFilter } from '../components/TabularExplorer/types'
27
+ import { parseDateValue } from './dates'
26
28
 
27
29
  export function hasFilterForColumn(filters: Record<string, ColumnFilters>, column: string): boolean {
28
30
  const f = filters[column]
29
31
  if (!f) return false
30
- return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null)
32
+ return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null || f.date)
33
+ }
34
+
35
+ // `initialFilters` is a public prop of TabularExplorer, so a filter can carry
36
+ // anything a consumer put in it. An unparseable date is dropped rather than
37
+ // thrown, the way a non-numeric `min` is already ignored by `Number.isFinite`.
38
+ export function parseIsoDate(value: string | undefined): CalendarDate | null {
39
+ if (!value) return null
40
+ try {
41
+ return parseDate(value)
42
+ }
43
+ catch {
44
+ return null
45
+ }
46
+ }
47
+
48
+ /**
49
+ * The calendar day a cell of a date column falls on, as an ISO date, or null
50
+ * when the value is not one the API produced. Timestamps keep only their day:
51
+ * filtering a whole day is the useful reading of "filter by this value", where
52
+ * the exact millisecond would only ever match that one row.
53
+ */
54
+ export function toIsoDay(value: unknown): string | null {
55
+ const day = String(value ?? '').slice(0, 10)
56
+ return parseIsoDate(day) ? day : null
57
+ }
58
+
59
+ /**
60
+ * The day interval a date filter selects, half-open: `[lower, upper)`.
61
+ * An absent bound means the interval is open on that side.
62
+ */
63
+ function dateFilterBounds(filter: DateFilter): { lower: CalendarDate | null, upper: CalendarDate | null } {
64
+ const start = parseIsoDate(filter.start)
65
+ if (!start) return { lower: null, upper: null }
66
+ switch (filter.operator) {
67
+ case 'is':
68
+ return { lower: start, upper: start.add({ days: 1 }) }
69
+ case 'before':
70
+ return { lower: null, upper: start }
71
+ case 'after':
72
+ return { lower: start.add({ days: 1 }), upper: null }
73
+ case 'between': {
74
+ const end = parseIsoDate(filter.end)
75
+ return { lower: start, upper: end ? end.add({ days: 1 }) : null }
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Query params for a date filter, as a half-open day interval.
82
+ *
83
+ * The same two operators cover `date` and `datetime` columns, which
84
+ * `resolveColumnType` merges into one display type. `__exact` would not: a
85
+ * timestamp is never equal to a bare day, so an exact filter silently matches
86
+ * nothing on a `datetime` column.
87
+ */
88
+ export function buildDateFilterParams(column: string, filter: DateFilter): Record<string, string> {
89
+ const { lower, upper } = dateFilterBounds(filter)
90
+ const params: Record<string, string> = {}
91
+ if (lower) params[`${column}__greater`] = lower.toString()
92
+ if (upper) params[`${column}__strictly_less`] = upper.toString()
93
+ return params
31
94
  }
32
95
 
33
96
  export type TypeDisplay = {
@@ -42,9 +105,19 @@ export function buildTypeConfig(t: TranslationFunction): Record<ColumnType, Type
42
105
  text: { icon: RiText, label: t('Texte') },
43
106
  date: { icon: RiCalendarLine, label: t('Date') },
44
107
  boolean: { icon: RiCheckboxLine, label: t('Booléen') },
108
+ year: { icon: RiCalendarLine, label: t('Année') },
45
109
  }
46
110
  }
47
111
 
112
+ export function resolveColumnType(colInfo: { python_type: string, format?: string }, isCategorical: boolean): ColumnType {
113
+ if (colInfo.format === 'year') return 'year'
114
+ if (['int', 'float'].includes(colInfo.python_type)) return 'number'
115
+ if (['date', 'datetime'].includes(colInfo.python_type)) return 'date'
116
+ if (colInfo.python_type === 'bool') return 'boolean'
117
+ if (isCategorical) return 'categorical'
118
+ return 'text'
119
+ }
120
+
48
121
  // csv-detective formats that carry no semantic meaning beyond the generic
49
122
  // display type already resolved by `ColumnType` — these fall back to
50
123
  // `buildTypeConfig` (Texte / Nombre / Date / Booléen) in the header.
@@ -138,8 +211,8 @@ export function useFormatTabular() {
138
211
 
139
212
  function formatCellDate(value: unknown): string {
140
213
  if (value == null || value === '') return '–'
141
- const d = new Date(String(value))
142
- if (Number.isNaN(d.getTime())) return String(value)
214
+ const d = parseDateValue(String(value))
215
+ if (!d) return String(value)
143
216
  return new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(d)
144
217
  }
145
218
 
@@ -149,6 +222,48 @@ export function useFormatTabular() {
149
222
  const TRUTHY_VALUES = ['true', '1', 'oui', 'yes']
150
223
  const FALSY_VALUES = ['false', '0', 'non', 'no']
151
224
 
225
+ // `encodeURIComponent` leaves `.`, `(` and `)` as-is, but they are the operator
226
+ // separator and the delimiters of the API's `or(...)` grammar: a search value
227
+ // containing one makes the parser reject the whole query with a 400. Wrapping
228
+ // the value in double quotes (as the API README suggests) does not work here —
229
+ // the API keeps them as part of the searched string and returns no result. It
230
+ // does percent-decode the value after parsing, so encoding them is enough.
231
+ function encodeConditionValue(value: string): string {
232
+ return encodeURIComponent(value)
233
+ .replace(/\./g, '%2E')
234
+ .replace(/\(/g, '%28')
235
+ .replace(/\)/g, '%29')
236
+ }
237
+
238
+ // A decimal literal, not `Number()`: the API compares against a number column,
239
+ // and it answers an error for the whole `or(...)` when it is handed something it
240
+ // cannot parse as one — which `Number()` happily accepts (`0x10`, `1e5`, ` `).
241
+ const NUMBER_LITERAL_RE = /^-?\d+(\.\d+)?$/
242
+
243
+ /**
244
+ * Builds the OR conditions for global search across all columns.
245
+ * Text and categorical columns get a `__contains` filter; number columns
246
+ * get a `__exact` filter only when the search value is numeric.
247
+ * Year, date and boolean columns are excluded.
248
+ */
249
+ export function buildGlobalSearchConditions(
250
+ allColumns: string[],
251
+ getColumnType: (col: string) => ColumnType,
252
+ searchValue: string,
253
+ ): string[] {
254
+ const conditions: string[] = []
255
+ for (const col of allColumns) {
256
+ const type = getColumnType(col)
257
+ if (type === 'text' || type === 'categorical') {
258
+ conditions.push(col + '__contains.' + encodeConditionValue(searchValue))
259
+ }
260
+ else if (type === 'number' && NUMBER_LITERAL_RE.test(searchValue)) {
261
+ conditions.push(col + '__exact.' + encodeConditionValue(searchValue))
262
+ }
263
+ }
264
+ return conditions
265
+ }
266
+
152
267
  export function isTruthy(value: unknown): boolean {
153
268
  if (typeof value === 'boolean') return value
154
269
  if (typeof value === 'string') return TRUTHY_VALUES.includes(value.toLowerCase())
@@ -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
@@ -15,7 +15,7 @@ import type { Owned, OwnedWithFullObject, OwnedWithId } from './types/owned'
15
15
  import type { Comment, Thread } from './types/discussions'
16
16
  import type { PageBloc, ContentBloc, BlocWithTitle, DatasetsListBloc, DataservicesListBloc, ReusesListBloc, LinkInBloc, LinksListBloc, MarkdownBloc, AccordionItemBloc, AccordionListBloc, HeroBloc } from './types/pages'
17
17
  import type { Post } from './types/posts'
18
- import type { ReuseReference, NewReuse, Reuse, ReuseTopic, ReuseType } from './types/reuses'
18
+ import type { ReuseReference, NewReuse, Reuse, ReuseV2, ReuseTopic, ReuseType } from './types/reuses'
19
19
  import type { RegisteredSchema, Schema, SchemaDetails, SchemaField, SchemaPath, SchemaPublicationMode, SchemaResponseData, SchemaVersion, ValidataError } from './types/schemas'
20
20
  import type { TopicV2, TopicElement, TopicElementClass, TopicElementRel } from './types/topics'
21
21
  import type { CommunityResource, FileResourceFileType, RemoteResourceFileType, ResourceFileType, ResourceGroup, ResourceType, Resource } from './types/resources'
@@ -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 { ColumnFilters, ColumnType, TabularRow } 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'
@@ -37,8 +38,12 @@ import Avatar from './components/Avatar.vue'
37
38
  import AvatarWithName from './components/AvatarWithName.vue'
38
39
  import BannerAction from './components/BannerAction.vue'
39
40
  import BrandedButton from './components/BrandedButton.vue'
41
+ import ChartCard from './components/ChartCard.vue'
40
42
  import CopyButton from './components/CopyButton.vue'
41
43
  import DataserviceCard from './components/DataserviceCard.vue'
44
+ import DataserviceQuality from './components/DataserviceQuality.vue'
45
+ import DataserviceQualityInline from './components/DataserviceQualityInline.vue'
46
+ import DataserviceQualityTooltipContent from './components/DataserviceQualityTooltipContent.vue'
42
47
  import DatasetCard from './components/DatasetCard.vue'
43
48
  import DataStructure from './components/ResourceAccordion/DataStructure.vue'
44
49
  import Downloads from './components/ResourceAccordion/Downloads.vue'
@@ -47,14 +52,15 @@ import DescriptionListTerm from './components/DescriptionListTerm.vue'
47
52
  import DescriptionListDetails from './components/DescriptionListDetails.vue'
48
53
  import DiscussionMessageCard from './components/DiscussionMessageCard.vue'
49
54
  import DateRangeDetails from './components/DateRangeDetails.vue'
55
+ import FormattedDate from './components/FormattedDate.vue'
50
56
  import { DatasetInformationSection, DatasetTemporalitySection, DatasetSpatialSection, DatasetSchemaSection, DatasetEmbedSection } from './components/DatasetInformation'
51
57
  import LeafletMap from './components/LeafletMap.vue'
52
58
  import LicenseBadge from './components/LicenseBadge.vue'
53
59
  import Tag from './components/Tag.vue'
54
60
  import DatasetQuality from './components/DatasetQuality.vue'
55
61
  import DatasetQualityInline from './components/DatasetQualityInline.vue'
56
- import DatasetQualityItem from './components/DatasetQualityItem.vue'
57
- import DatasetQualityScore from './components/DatasetQualityScore.vue'
62
+ import QualityItem from './components/QualityItem.vue'
63
+ import QualityScore from './components/QualityScore.vue'
58
64
  import ProgressBar from './components/ProgressBar.vue'
59
65
  import DatasetQualityTooltipContent from './components/DatasetQualityTooltipContent.vue'
60
66
  import ExtraAccordion from './components/ExtraAccordion.vue'
@@ -104,6 +110,9 @@ import SelectGroup from './components/Form/SelectGroup.vue'
104
110
  import Listbox from './components/Form/Listbox.vue'
105
111
  import InfiniteLoader from './components/InfiniteLoader.vue'
106
112
  import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
113
+ import TabularMobileFilters from './components/TabularExplorer/TabularMobileFilters.vue'
114
+ import TabularTable from './components/TabularExplorer/TabularTable.vue'
115
+ import TabularToolbar from './components/TabularExplorer/TabularToolbar.vue'
107
116
  import type { UseFetchFunction } from './functions/api.types'
108
117
  import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
109
118
  import { ofetch } from 'ofetch'
@@ -119,6 +128,8 @@ export * from './composables/useTranslation'
119
128
  export * from './composables/useHasTabularData'
120
129
  export * from './composables/useResourceCapabilities'
121
130
  export * from './composables/useTabularProfile'
131
+ export * from './composables/useDatasetResources'
132
+ export * from './composables/useResizable'
122
133
 
123
134
  export * from './functions/activities'
124
135
  export * from './functions/datasets'
@@ -227,6 +238,7 @@ export type {
227
238
  ResourceType,
228
239
  ReuseReference,
229
240
  Reuse,
241
+ ReuseV2,
230
242
  ReuseTopic,
231
243
  ReuseType,
232
244
  Schema,
@@ -251,6 +263,12 @@ export type {
251
263
  Chart,
252
264
  ChartForm,
253
265
  ChartForApi,
266
+ CombinedSort,
267
+ ColumnDefinition,
268
+ ColumnFilters,
269
+ ColumnType,
270
+ ColumnsDefinition,
271
+ TabularRow,
254
272
  FilterCondition,
255
273
  Filter,
256
274
  AndFilters,
@@ -327,8 +345,12 @@ export {
327
345
  AvatarWithName,
328
346
  BannerAction,
329
347
  BrandedButton,
348
+ ChartCard,
330
349
  CopyButton,
331
350
  DataserviceCard,
351
+ DataserviceQuality,
352
+ DataserviceQualityInline,
353
+ DataserviceQualityTooltipContent,
332
354
  DatasetCard,
333
355
  DataStructure,
334
356
  Downloads,
@@ -343,10 +365,11 @@ export {
343
365
  DiscussionMessageCard,
344
366
  DatasetQuality,
345
367
  DatasetQualityInline,
346
- DatasetQualityItem,
347
- DatasetQualityScore,
368
+ QualityItem,
369
+ QualityScore,
348
370
  DatasetQualityTooltipContent,
349
371
  DateRangeDetails,
372
+ FormattedDate,
350
373
  ExtraAccordion,
351
374
  LabelTag,
352
375
  LeafletMap,
@@ -399,4 +422,7 @@ export {
399
422
  Listbox,
400
423
  InfiniteLoader,
401
424
  TabularExplorer,
425
+ TabularMobileFilters,
426
+ TabularTable,
427
+ TabularToolbar,
402
428
  }
@@ -31,6 +31,20 @@ export type BaseDataservice = Owned & WithAccessType & {
31
31
 
32
32
  export type NewDataservice = Omit<BaseDataservice, keyof OwnedWithId> & OwnedWithId
33
33
 
34
+ export type DataserviceQuality = {
35
+ has_description: boolean
36
+ has_machine_documentation: boolean
37
+ has_technical_documentation: boolean
38
+ has_business_documentation: boolean
39
+ license: boolean
40
+ has_contact_point: boolean
41
+ has_base_api_url: boolean
42
+ availability_documented: boolean
43
+ rate_limiting_documented: boolean
44
+ access_conditions_clear: boolean
45
+ score: number
46
+ }
47
+
34
48
  export type Dataservice = Owned & WithAccessType & {
35
49
  acronym: string
36
50
  archived_at: string | null
@@ -72,4 +86,5 @@ export type Dataservice = Owned & WithAccessType & {
72
86
  slug: string
73
87
  tags: Array<string>
74
88
  title: string
89
+ quality?: DataserviceQuality
75
90
  }
@@ -1,5 +1,6 @@
1
1
  import type { User } from './users'
2
2
  import type { Badges } from './badges'
3
+ import type { PageBloc } from './pages'
3
4
 
4
5
  export type MemberRole = 'admin' | 'editor' | 'partial_editor'
5
6
 
@@ -68,4 +69,13 @@ export type Organization = {
68
69
  reuses_by_months: Record<string, number>
69
70
  views: number
70
71
  }
72
+ // Editorial blocs powering the organization "Présentation" tab. Excluded from
73
+ // the default API read mask, so only present when requested with X-Fields.
74
+ // Read through the API's `public_presentation_blocs`: hidden from the public until
75
+ // published, but always returned to organization administrators.
76
+ presentation_blocs?: Array<PageBloc>
77
+ // Publication date of the blocs. `null` means draft (never public); a set date
78
+ // means published. Like `presentation_blocs`, only present when requested with
79
+ // X-Fields.
80
+ presentation_blocs_published_at?: string | null
71
81
  }
@@ -1,5 +1,5 @@
1
1
  import type { Owned, OwnedWithId } from './owned'
2
- import type { Dataset } from './datasets'
2
+ import type { Dataset, Rel } from './datasets'
3
3
  import type { Badges } from './badges'
4
4
  import type { Dataservice } from './dataservices'
5
5
 
@@ -51,6 +51,17 @@ export type Reuse = BaseReuse & {
51
51
  permissions: { edit: boolean, delete: boolean }
52
52
  }
53
53
 
54
+ /**
55
+ * Lightweight reuse returned by the listing endpoints (`/api/2/reuses/` and
56
+ * `/api/2/reuses/search/`): the `datasets` and `dataservices` reference lists
57
+ * are replaced by links to their respective listing endpoints filtered on this
58
+ * reuse, so that listing reuses does not dereference every linked dataset.
59
+ */
60
+ export type ReuseV2 = Owned & Omit<Reuse, 'datasets' | 'dataservices'> & {
61
+ datasets: Rel
62
+ dataservices: Rel
63
+ }
64
+
54
65
  export type ReuseType = {
55
66
  id: string
56
67
  label: string
@@ -4,7 +4,7 @@ import type { AccessType } from './access_types'
4
4
  import type { Dataset } from './datasets'
5
5
  import type { Dataservice } from './dataservices'
6
6
  import type { Organization } from './organizations'
7
- import type { Reuse } from './reuses'
7
+ import type { ReuseV2 } from './reuses'
8
8
  import type { TopicV2 } from './topics'
9
9
  import type {
10
10
  CERTIFIED,
@@ -372,7 +372,7 @@ export type GlobalSearchConfig = SearchTypeConfig[]
372
372
  export type SearchResponseByClass = {
373
373
  datasets: DatasetSearchResponse<Dataset>
374
374
  dataservices: DataserviceSearchResponse<Dataservice>
375
- reuses: ReuseSearchResponse<Reuse>
375
+ reuses: ReuseSearchResponse<ReuseV2>
376
376
  organizations: OrganizationSearchResponse<Organization>
377
377
  topics: TopicSearchResponse<TopicV2>
378
378
  }
@@ -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 = {
@@ -66,6 +67,7 @@ export type Chart = Owned & {
66
67
  created_at: string
67
68
  last_modified: string
68
69
  deleted_at: string | null
70
+ image: string | null
69
71
  uri: string
70
72
  page: string
71
73
  x_axis: XAxis
@@ -87,3 +89,6 @@ export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organ
87
89
  chart_type?: DataSeriesType | null
88
90
  filter: GenericFilter | null
89
91
  }
92
+
93
+ export type ColumnDefinition = { name: string, type: ColumnType, min?: number, max?: number }
94
+ export type ColumnsDefinition = Record<string, Array<ColumnDefinition>>
@@ -1,61 +0,0 @@
1
- import { defineComponent as _, ref as g, computed as h, onMounted as S, nextTick as w, openBlock as l, createElementBlock as k, renderSlot as C, toDisplayString as r, unref as a, createBlock as n, withCtx as o, createTextVNode as u, createCommentVNode as b } from "vue";
2
- import { c6 as B, bm as E, bk as L, _ as c } from "./main-DKu5SOAl.js";
3
- const R = { class: "text-xs" }, q = {
4
- key: 1,
5
- class: "text-gray-medium"
6
- }, V = /* @__PURE__ */ _({
7
- __name: "PreviewWrapper",
8
- props: {
9
- fileType: {},
10
- resource: {},
11
- maxSize: {},
12
- load: { type: Function }
13
- },
14
- emits: ["loaded"],
15
- setup(s, { emit: x }) {
16
- const i = s, z = x, { t } = B(), p = g(null), d = g(!1), f = g(null), y = h(() => E(i.resource)), T = h(() => L(i.resource)), v = h(() => {
17
- const e = y.value, m = i.maxSize;
18
- return !e || !m ? !1 : e <= m;
19
- });
20
- return S(async () => {
21
- if (!(!v.value || T.value === "blocked")) {
22
- d.value = !0;
23
- try {
24
- p.value = await i.load(), await w(), z("loaded");
25
- } catch (e) {
26
- console.error("Error loading preview:", e), f.value = e instanceof TypeError ? "network" : "generic";
27
- } finally {
28
- d.value = !1;
29
- }
30
- }
31
- }), (e, m) => (l(), k("div", R, [
32
- p.value !== null ? C(e.$slots, "default", {
33
- key: 0,
34
- data: p.value
35
- }) : d.value ? (l(), k("div", q, r(a(t)("Chargement de l'aperçu {fileType}...", { fileType: s.fileType })), 1)) : v.value ? T.value === "blocked" ? (l(), n(c, { key: 3 }, {
36
- default: o(() => [
37
- u(r(a(t)("Ce fichier {fileType} ne peut pas être prévisualisé car il est hébergé sur un site distant qui restreint l'accès (CORS). Téléchargez-le depuis l'onglet Téléchargements.", { fileType: s.fileType })), 1)
38
- ]),
39
- _: 1
40
- })) : f.value === "network" ? (l(), n(c, { key: 4 }, {
41
- default: o(() => [
42
- u(r(a(t)("Ce fichier est hébergé sur un site externe qui ne permet pas la prévisualisation. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
43
- ]),
44
- _: 1
45
- })) : f.value ? (l(), n(c, { key: 5 }, {
46
- default: o(() => [
47
- u(r(a(t)("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
48
- ]),
49
- _: 1
50
- })) : b("", !0) : (l(), n(c, { key: 2 }, {
51
- default: o(() => [
52
- u(r(y.value ? a(t)("Le fichier {fileType} est trop volumineux pour être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.", { fileType: s.fileType }) : a(t)("La taille du fichier est inconnue, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
53
- ]),
54
- _: 1
55
- }))
56
- ]));
57
- }
58
- });
59
- export {
60
- V as _
61
- };